题意:
给出长度为n(1 <= n <= 1e5)的数列,数列中的数逐渐递增(1 <= ai <= 1e5),问最多能找出长度为多少的序列,满足新序列中相邻的两个数不互素(即gcd(ai, ai+1) > 1 )?
方法:
遍历一遍数组,将当前的数分解质因子,将该数ai的所有质因子存到数组p中。另外,建立数组dp,dp[j]表示质因子j的当前最长序列长度。分解完质因子之后,遍历数组p,更新目前的最长序列长度,用maxn表述长度,则maxn = max(dp[j] + 1, maxn); (这里的dp[j]表示通过因子j与上一个含有因子j的数且长度最长的数相连,则ai可以与该数通过j连在一起,所以dp[j]+1。更新ai的所有质因子,更新最长的长度)。接着,用更新得到的以ai结尾的最长长度,来赋值给ai所含有的所有质因子的最长长度dp[j](以该数结尾的数,最长长度赋值给含有的每个质因子,因为这代表这以这些因子结尾的数最长长度也是那个长度)。最后,遍历所有素数,找到最大长度。
思路好难写,直接上代码吧
1 //#include<bits/stdc++.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <string> 7 #include <cmath> 8 #include <cstdlib> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <vector> 13 #include <set> 14 15 using namespace std; 16 typedef long long LL; 17 typedef pair<int, int> pii; 18 const int INF = 0x7fffffff; 19 const int MAXN = 1e5 + 10; 20 int a[MAXN]; 21 int prime[MAXN+1]; 22 int p[MAXN]; 23 int dp[MAXN]; 24 int n; 25 26 void getPrime() { 27 memset(prime, 0, sizeof(prime)); 28 for(int i = 2; i <= MAXN; i++) { 29 if(!prime[i]) prime[++prime[0]] = i; 30 for(int j = 1; j <= prime[0] && prime[j] <= MAXN / i; j++) { 31 prime[prime[j]*i] = 1; 32 if(i % prime[j] == 0) break; 33 } 34 } 35 } 36 37 void solve() { 38 for(int i = 0; i < n; i++) { 39 int num = a[i], cnt = 0; 40 for(int j = 1; j <= prime[0]; j++) { 41 bool flag = false; 42 while(num % prime[j] == 0) { 43 flag = true; 44 num /= prime[j]; 45 } 46 if(flag) p[cnt++] = prime[j]; 47 if(num == 1) break; 48 } 49 int maxn = 0; 50 for(int j = 0; j < cnt; j++) 51 maxn = max(dp[p[j]] + 1, maxn); 52 for(int j = 0; j < cnt; j++) 53 dp[p[j]] = maxn; 54 } 55 int ans = 1; 56 for(int i = 1; i <= prime[0]; i++) 57 ans = max(ans, dp[prime[i]]); 58 printf("%d\n", ans); 59 } 60 61 int main(){ 62 #ifdef local 63 freopen("case.in", "r", stdin); 64 #endif 65 getPrime(); 66 // for(int i = 1; i <= 10; i++) 67 // cout << prime[i] << " "; 68 // cout << endl; 69 scanf("%d", &n); 70 for(int i = 0; i < n; i++) 71 scanf("%d", &a[i]); 72 solve(); 73 return 0; 74 }