动态规划

来源:互联网 发布:魔据大数据 编辑:程序博客网 时间:2024/06/08 08:11

香樟树
Time Limits: 1000 ms
Memory Limits: 65536 KB

Description

  被誉为江南四大名木之一的香樟树很有特色,它的树皮粗糙,质地却很均匀,从来没有白杨树的斑斑驳驳、没有柳树的肿瘤结节;树枝树干一分为二、二分为四一路长去,不会偷工减料也不会画蛇添足;树冠的形态是球形的,在天空中画出优美的曲线。
  除了上述优点之外,香樟树还有一个秘密武器。那就是……………………它凭借朴实、厚重的优秀品格赢得了小狐狸的青睐!!!
  话说有一天,小狐狸正在湖边散步,忽然一阵风吹来,她赶紧闭上眼睛。当她再次睁开眼睛时,发现美丽的湖畔多出了一排整齐的香樟树。小狐狸非常兴奋,她对每棵树都观察入微,并且数出了它们的叶子个数。她觉得如果相邻两棵树的叶子个数互素是不和谐的。因此小狐狸想从一排香樟树中选出若干棵,在满足相邻两棵树的叶子个数不互素的条件下,使得树尽量多。

Input

  第一行一个正整数n,表示有n棵香樟树。
  第二行n个正整数,第i个数表示第i棵香樟树叶子的个数。

Output

  一个正整数,表示最多能选多少棵树。

Sample Input

6
6 2 3 15 8 5

Sample Output

4

Data Constraint

Hint

【样例解释】
  选择第1、第3、第4和第6棵树

【数据范围】
  对于60%的数据n<=1000
  对于100%的数据 n<=100000,叶子个数<=100000
【注意】
  选中的树不能改变其位置,即如果选中第(t1,t2,t3……tn)棵树
  其中t1 < t2 < t3 < …… < tn则认为ti与ti+1相邻

思路1 最长子序列问题
可以把这个问题看作一个子序列问题。相比最长上升子序列,只用把if(num[i]>num[j]) 改为 if(gcd(num[i], num[j]) != 1) 即可。时间复杂度为O(N^2)。
这种方法只能得60分。

思路2 更改状态
之前的状态 f[i] 为 从1到i最多能留下的树的棵数。注意到,两个数不互素的意思就是两个数有相同的质因数,我们可以考虑在质因数上面做文章。我们把新的状态 f[i] 定义为 以叶子数的质因数包含i的树结尾,最多能留下的树的棵数。读入每棵树的叶子数时,我们根本不用保存它,只需要将它分解,根据分解出的质因数和当前的 f[i] 算出以这个数结尾的最大长度,最后再分解一次来更新 f[i]。答案为 f[i] 的最大值。时间复杂度为O(N^1.5)。

参考代码

#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <string>#include <iostream>#include <algorithm>#include <vector>#include <stack>#include <queue>#include <deque>#include <map>#include <set>using std::cin;using std::cout;using std::endl;int n;int maxLengthOfPrime[100005]; //f[i]void divide(int num){    int origin=num;    int tempLength=0;    //第一次分解:算出目前能以这个数作为结尾的最长序列的长度     int limit=sqrt(num);    for(int i=2; i<=limit; i++)    {        if(num%i) continue;        tempLength=std::max(tempLength,maxLengthOfPrime[i]);        while(num%i==0) num/=i;    }    if(num!=1)    {        tempLength=std::max(tempLength,maxLengthOfPrime[num]);    }    //加上这个数的话长度就加1     tempLength++;    //第二次分解:更新状态     num=origin;    for(int i=2; i<=limit; i++)    {        if(num%i) continue;        //以num结尾的最长序列长度为tempLength,i为num的质因数,所以f[i]更新为tempLength        maxLengthOfPrime[i]=tempLength;        while(num%i==0) num/=i;    }    if(num!=1)    {        maxLengthOfPrime[num]=tempLength;    }}int main(){    int maxNum=0;    scanf("%d",&n);    for(int i=1; i<=n; i++)    {        int input;        scanf("%d",&input);        //保存最大的数,最后我们在2到maxNum中寻找答案         maxNum=std::max(maxNum,input);        divide(input);    }    int ans=0;    for(int i=2; i<=maxNum; i++)    {        //找最大的即为答案         ans=std::max(ans,maxLengthOfPrime[i]);    }    printf("%d",ans);    return 0;}