混沌DM

DM Hunter

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

http://codeforces.com/problemset/problem/264/B

题目意思

  给定一个上升子序列,要你求一个最长子序列的长度,满足任意相邻两项均不互质。

首先注意一下,长度至少为1,而且当长度为1时,序列 1 也是可以的。

虽然1与任何数都互质,但长度为1的序列没有任意相邻两项,不过好在这组数据一开始就在测试数据中。不然这题的hack就要精彩很多了。

首先很容易想到n^2的DP,dp[j]表示以第j个数结尾的序列的最长长度。

  dp[j] = max(dp[k] + 1, 0<=k<j && gcd(num[k], num[j])>1)

大量的工作耗费在了计算gcd上。

所以,需要换一个状态。dp[i]表示 当前最后一项含素因子i的最长序列。

这样每次,增加一个数num时,它可以接在任何含num的素因子的序列后面。访问所有素因子的dp值,求出最大值为ans。

同时,它所有的素因子的dp[i]也更新为ans+1

预处理素数后,每次的转移费用就是这个num素因子的个数,时间绰绰有余了。

代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=100100;
 5 int n,a[N];
 6 int pr[N],p[N/10],lp;
 7 void gp(){
 8     for(int i=2;i<N;i++)pr[i]=i;
 9     for(int i=2;i<N;i++){
10         if(pr[i]==i)p[lp++]=i;
11         for(int j=0;j<lp && i*p[j]<N;j++){
12             pr[i*p[j]]=p[j];
13             if(i%p[j]==0)break;
14         }
15     }
16 }
17 void gn(int n,int &l,int b[],int f[]){
18     int t;
19     l=0;
20     while(n>1){
21         t=pr[n];
22         f[l]=0;
23         while(n%t==0)
24             n/=t,f[l]++;
25         b[l++]=t;
26     }
27 }
28 int dp[N];
29 int main()
30 {
31     gp();
32     int l,b[50],f[50];
33     while (~scanf("%d",&n))
34     {
35         for(int i=0;i<n;i++)scanf("%d",a+i);
36         memset(dp,0,sizeof(dp));
37         for(int i=0;i<n;i++){
38             if(a[i]==1)continue;
39             gn(a[i],l,b,f);
40             int tmp=dp[b[0]];
41             for(int i=1;i<l;i++)
42                 if(dp[b[i]]>tmp)
43                     tmp=dp[b[i]];
44             for(int i=0;i<l;i++)
45                 dp[b[i]]=tmp+1;
46         }
47         int ans=1;
48         for(int i=0;i<N;i++)if(dp[i]>ans)ans=dp[i];
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

 

 

posted on 2013-01-21 19:36  混沌DM  阅读(472)  评论(0编辑  收藏  举报