题目
题意:
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;
}
/**/