Intelligent Warehouse
给出一个长度为n<1e5的数组a
其中ai<1e7
求一个它的最大子集
使得其中的任意两数互为倍数因子关系
设dp[i]表示当前选的所有数都是i的因子的最优解(最大值)
此题能开int 1e7大小的数组
最直观的转移就是用dp[i]更新所有i的倍数的dp值 即
1 2 3 4 5 6 7 8
| for(int i=1;i<=Max;i++){ dp[i]+=cnt[i]; if(!cnt[i])continue; for(int j=2*i;j<=Max;j+=i)dp[j]=max(dp[j],dp[i]); ans=max(ans,dp[i]); }
|
这样极限复杂度超过1e8
实际上就只用枚举i的素数倍就可以 因为合数可以倍若干个素数乘积凑出来
没必要再枚举
比如 i=30
我只用枚举它的素数倍即更新
dp[30×2]=max(dp[30×2],dp[30])…..dp[30×5]=max(dp[30×5],dp[30])
那为什么不用更新dp[30×6]?
因为在枚举它的素数倍时已经更新了dp[30×2]和dp[30×3]
dp[30×6] 会在之后dp[60×3]和dp[90×2]被更新到
复杂度和埃氏筛相同(?个人记得这个是nlogn的复杂度) 为O(XloglogX) 其中X=1e7
1e7内的素数可以通过欧拉筛或埃氏筛处理
1 2 3 4 5 6
| for(int i=2;i<=Max;i++){ if(isprime[i]){ for(int j=2*i;j<=Max;j++)isprime[i]=0; } }
|
不加埃氏筛直接处理它的所有倍数 可以卡进1s但是理论复杂度超过1e8
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
| #include <bits/stdc++.h> #include <time.h> using namespace std; typedef long long ll; #define endl '\n' #define Turnoff std::ios::sync_with_stdio(false) #define P pair<ll,ll> const int Max=1e7+5; const int Mod=998244353; const int inf=0x3f3f3f3f;
int dp[Max],cnt[Max]; int main() { Turnoff; int n;cin>>n; for(int i=0;i<n;i++){ int temp;cin>>temp; cnt[temp]++; } int ans=0; for(int i=1;i<=Max;i++){ dp[i]+=cnt[i]; if(!cnt[i])continue; for(int j=2*i;j<=Max;j+=i)dp[j]=max(dp[j],dp[i]); ans=max(ans,dp[i]); } cout<<ans<<endl;
}
|