题意:
n个数字,问存在的最长的一组数,使得其中任意两个数的都是倍数关系,问最长的长度是多少
题解:
暴力。。。
没想到暴力就能做,当时就该交上去试试的
用dp[i]表示当期选的所有数都是i的约数且符合题意的情况下所能选的个数的最大值
最直观的转移就是dp[i]取更新i的所有倍数的dp值
复杂度是O(WlogW),没想到竟然不会tle。。。
正解:
只用枚举i的素数倍数即可,因为合数总可以用若干个素数的乘积给凑出来
时间复杂度(O(W log log W))
代码:
暴力:
//A
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e7+5;
int n,a[200005],cnt[maxn],dp[maxn],ans,maxx;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
maxx=max(maxx,a[i]);
cnt[a[i]]++;
}
for(int i=1;i<maxn;i++){
if(!cnt[i]) continue;
dp[i]+=cnt[i];
for(int j=i<<1;j<maxn;j+=i){
if(cnt[j]) dp[j]=max(dp[i],dp[j]);
}
}
for(int i=1;i<=maxx;i++) ans=max(ans,dp[i]);
printf("%d\n",ans);
}
正解:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=100005;
int mod=1e9+7;
const int nn=1e7+5;
int prime[nn],vis[nn],cnt;
void eularsie(int n) {
cnt=0;
for(int i=2;i<=n;i++) {
if(!vis[i]) {
prime[cnt++]=i;
}
for(int j=0;j<cnt&&i*prime[j]<=n;j++) {
if(!vis[i*prime[j]]) {
vis[i*prime[j]]=1;
}
if(i%prime[j]==0) break;
}
}
}
int a[nn],dp[nn];
int main() {
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
eularsie(1e7);
int n;
cin>>n;
for(int i=0;i<n;i++) {
int x;
cin>>x;
a[x]++;
}
int ans=0;
for(int i=1;i<=1e7;i++) {
dp[i]+=a[i];
ans=max(ans,dp[i]);
for(int j=0;j<cnt&&i*prime[j]<=1e7;j++) {
dp[i*prime[j]]=max(dp[i*prime[j]],dp[i]);
}
}
cout<<ans<<'\n';
return 0;
}
/* */