题目

题意:

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;
}
/* */