dp + 筛最小素因子 + 枚举最小素因子
切分数组:
给定一个整数数组 nums ,小李想将 nums 切割成若干个非空子数组,使得每个子数组最左边的数和最右边的数的最大公约数大于 1 。为了减少他的工作量,请求出最少可以切成多少个子数组。
示例 1:
输入:nums = [2,3,3,2,3,3]
输出:2
解释:最优切割为 [2,3,3,2] 和 [3,3] 。第一个子数组头尾数字的最大公约数为 2 ,第二个子数组头尾数字的最大公约数为 3 。
示例 2:
输入:nums = [2,3,5,7]
输出:4
解释:只有一种可行的切割:[2], [3], [5], [7]
限制:
- 1 <= nums.length <= 10^5
- 2 <= nums[i] <= 10^6
思路:
- 首先我们先筛出最大数据以内(包括最大数据)所有数对应的最小素因子
- 推导dp方程
1:当前i位置所对应的数的组数 = min(当前i位置对应的最小素因子的位置,dp[i]+1)
2:当前i位置对应的最小素因子的位置= min(min[a[i]],dp[i-1])
- 枚举每个数的最小的最小素因子所对应的位置
因为当前数可能有好多素因子,所以我们把他除以他的最小素因子,呢么得到的数就会对应本身的最小素因子
参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <cstdio> #include <algorithm> #include <vector> #include <iostream> #include <map> #include <queue> #include <cstring> #include <string> #include <cstdlib> #include <cmath> #include <set> using namespace std; const int inf = (1 << 30); typedef long long ll; const int maxn = 1e6 + 5; int pr[1000005], mpr[1000005], dp[1000005], a[1000005],mpos[1000005]; void solv(int m) //筛x的最小素因子 { int cnt = 0; for (int i = 2; i <= m; i++) { if (!mpr[i]) pr[++cnt] = i, mpr[i] = i; for (int j = 1; j <= cnt; j++) { if (pr[j] * i > m||pr[j]>mpr[i]) break; mpr[pr[j] * i] = pr[j]; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); int n,m; cin >> n; m=~0x3f; for (int i = 1; i <= n; i++) cin >> a[i],m=max(m,a[i]); solv(m); memset(dp,0x3f3f3f,sizeof dp); memset(mpos,0x3f3f3f3f,sizeof mpos); dp[0]=0; for(int i=1;i<=n;i++) { int temp=a[i]; while(temp>1) { int ans=mpr[temp]; //cout<<ans<<endl; mpos[ans]=min(mpos[ans],dp[i-1]);//得到当前最小素因子的最近位置 dp[i]=min(dp[i],mpos[ans]+1);//得到当前距离i的最小素因子的距离 temp/=ans; } } cout<<dp[n]<<endl; }
|
leecode 版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { int pr[1000005], mpr[1000005], dp[1000005], a[1000005],mpos[1000005]; void solv(int m) //筛m以内所有数的最小素因子 { int cnt = 0; for (int i = 2; i <= m; i++) { if (!mpr[i]) pr[++cnt] = i, mpr[i] = i; for (int j = 1; j <= cnt; j++) { if (pr[j] * i > m||pr[j]>mpr[i]) break; mpr[pr[j] * i] = pr[j]; } } } public: int splitArray(vector<int>& nums) { int n,m; n=nums.size(); m=~0x3f; for (int i = 0; i<n; i++) a[i+1]=nums[i],m=max(m,a[i+1]); solv(m); memset(dp,0x3f3f3f,sizeof dp); memset(mpos,0x3f3f3f3f,sizeof mpos); dp[0]=0; for(int i=1;i<=n;i++) { int temp=a[i]; while(temp>1) { int ans=mpr[temp]; //cout<<ans<<endl; mpos[ans]=min(mpos[ans],dp[i-1]);//得到当前最小素因子的最近位置 dp[i]=min(dp[i],mpos[ans]+1);//得到当前距离i的最小素因子的距离 temp/=ans; } } return dp[n]; } };
|