CF264B Good Sequences

题目大意:给定一个序列a1,a2,……,an,求满足以下要求的最长子序列:1.该序列是严格上升的,即x[i] < x[i+1](1<=i<=k-1),2.任意两个相邻的元素是非互质的,即gcd(x[i],x[i+1])>1(1<=i<=k-1)。(1<=n,a[i]<=105)

思路:我们先将序列排序,满足严格上升的条件,然后可以很容易的列出一个动态转移方程:if(gcd(f[i],f[j])>1) f[i]=max(f[i],f[j]+1);(1<=j<i),但这个复杂度是O(n^2)的,无法通过,那么我们考虑优化。我们仔细观察这个式子(大雾,发现每个数只和他因数的倍数有关,再仔细观察又发现,对于一个因数x,他的k倍一定比他的i倍(i<k)大,而且第二大的是这个数的(k-1)倍,那么我们只需要枚举每个数的因数,每个数只和他前一个因数的倍数有关,这样复杂度就变成O(n·log(n))的了;

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
const int MaxN=200000;
int n,a[MaxN],id[MaxN],tot[MaxN],f[MaxN],nmax,vis;
vector<int>fir[MaxN];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]),f[i]=1,tot[a[i]]=1;
    sort(a+1,a+n+1);nmax=a[n];
    for(int i=1;i<=n;++i) id[a[i]]=i;
    for(int i=2;i<=nmax;++i){vis=0;
        for(int j=i;j<=nmax;j+=i){
            if(tot[j]==1){
                if(vis!=0) fir[id[j]].push_back(vis);
                vis=id[j];
            }
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=0;j<fir[i].size();++j){
            f[i]=max(f[fir[i][j]]+1,f[i]);
        }
    }nmax=0;
    for(int i=1;i<=n;++i) nmax=max(nmax,f[i]);
    printf("%d
",nmax);
    return 0;
}
原文地址:https://www.cnblogs.com/X-rice/p/11218910.html