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 }