出处: Codeforces
主要算法:DP
难度:4.8
思路分析:
这题DP太难了……
最终的解法是,令f[i]表示存在因子i的一个数作为子序列结尾的子序列的最大长度。(定义都好难懂啊……)
现在想一想怎么转移……首先先预处理出对于每一个数a[i]的所有因数。既然相邻的两个数不能是互质的,我们只需要判断相邻两个数的最大公约数是否大于1就好了。
那么如何判断能否连起来呢?依次枚举a[i],并枚举刚才处理好的a[i]的因数。为什么好枚举因数, 因为所有因数如果在之前的数里出现过,那么当前的a[i]都可以接上去——这一点有点像LIS,选择所有因数中f值最大的去接上去,并且所有因数的f值都可以更新成与其中最大值相同的。因为
代码注意点:
……
Code
/** This Program is written by QiXingZhi **/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #include <cmath> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int N = 100010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w; } int n,cur,_max,ans; int a[N],f[N]; vector <int> factor[N]; inline void MadeFactor(int I){ int x = a[I]; int lim = floor(sqrt(x)); factor[I].push_back(x); for(int i = 2; i <= lim; ++i){ if(x % i == 0){ factor[I].push_back(i); if(i!=x/i) factor[I].push_back(x/i); } } } int main(){ // freopen(".in","r",stdin); n = r; for(int i = 1; i <= n; ++i){ a[i] = r; MadeFactor(i); for(int i = 1; i <= n; ++i){ _max = 0; int sz = factor[i].size(); for(int j = 0; j < sz; ++j){ cur = factor[i][j]; ++f[cur]; _max = Max(_max, f[cur]); } for(int j = 0; j < sz; ++j){ f[factor[i][j]] = _max; } } for(int i = 1; i <= a[n]; ++i){ ans = Max(ans, f[i]); } printf("%d",ans); return 0; }
原文地址:https://www.cnblogs.com/qixingzhi/p/9310133.html
时间: 2024-10-18 04:51:14