这道题折腾了好长时间,必须写一下。
大致题意:主要提议是要在一个数组种找一个数列满足这个数列相邻两个数之间一定有约束即(gcd>1)。
思路:一看就是dp的题目,数据1e5显然不能暴力。所以类似于最长上升子序列的思想,我用了一个数组表示当前约束为prime[i]最大连续长度。
接下来就好做了dp[i] = max(tag[k])k为num[i]所有约数。每次状态转移完更新tag数组就是将他所有的约束都更新为当前最大值。
最后扫描一边dp数组最大值即为答案。注意所有的约数必须都为素数,我一开始就错在了这里,然后就是编程上注意,我好tle了一次。
代码如下:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #define LEN 1001000 8 9 using namespace std; 10 11 int isprime[LEN], prime[LEN], top; 12 int n, dp[LEN], tag[LEN], num[LEN]; 13 14 void makeprime() 15 { 16 memset(prime, 0, sizeof prime); 17 memset(isprime, 0, sizeof isprime); 18 top = 0; 19 for(int i=2; i<100010; i++){ 20 if(isprime[i]==0) prime[top++] = i; 21 for(int j=0; j<top && prime[j]*i<100100; j++){ 22 isprime[prime[j]*i] = 1; 23 } 24 } 25 } 26 27 int solve(int x) 28 { 29 int ret = 0; 30 for(int i=0; x-1; i++){ 31 if(x%prime[i]==0) ret = max(ret, tag[prime[i]]); 32 while(x%prime[i]==0 && x)x = x/prime[i]; 33 } 34 return ret; 35 } 36 37 void reflesh(int x, int val) 38 { 39 for(int i=0; x-1; i++){ 40 if(x%prime[i]==0) tag[prime[i]] = max(tag[prime[i]], val); 41 while(x%prime[i]==0 && x)x = x/prime[i]; 42 } 43 } 44 45 int main() 46 { 47 // freopen("in.txt", "r", stdin); 48 // freopen("out.txt", "w", stdout); 49 50 while(scanf("%d", &n)!=EOF){ 51 makeprime(); 52 memset(dp, 0, sizeof dp); 53 memset(tag, 0, sizeof tag); 54 int ans = 0; 55 for(int i=0; i<n; i++){ 56 scanf("%d", &num[i]); 57 dp[i] = solve(num[i])+1; 58 reflesh(num[i], dp[i]); 59 ans = max(ans, dp[i]); 60 } 61 printf("%d ", ans); 62 } 63 return 0; 64 }