[题解] CF264B Good Sequences
前言
题意
给定一个数集 \(A\) ,求一个严格上升的序列使得序列每个数都属于 \(A\) ,且任意相邻的两个数不互质。求构造出的数列的最大长度。
思路
考虑 DP, 设 \(dp[i]\) 以 \(i\) 为质因数之一的数结尾的最大长度。
首先预处理分解质因数,对于 \(A\) 中的数字从小到大排序并去重。
一次遍历 \(A\) 中的数字,设当前遍历到的数为 \(a\) 。
则再对于 \(a\) 分解质因数,并使用 \(set\) 进行维护。
将这些质因数的 \(dp\) 值取 \(max\) ,易得 \(dp[i]=max+1\) ( \(i\) 为 \(a\) 的质因数)。
最后对 \(dp[i](i\in[1,100000])\) 取 \(max\) 即可。
总体时间复杂度为 \(O(n\log n)\) ,因为一个数的能都分解成的质因数不可能超过 \(\log n\) 个,当且仅当 \(n\) 为 \(2\) 的幂时取得到等号。还带上一个较小的常数,为 \(n\) 对数的对数,因为使用了 set 进行维护,因为太小,此题中必不会超过 \(5\) ,可看为常数。
Code
#include <set>
#include <cstdio>
#include <algorithm>
using namespace std;
namespace Quick_Function {
template <typename Temp> void Read(Temp &x) {
x = 0; char ch = getchar(); bool op = 0;
while(ch < '0' || ch > '9') { if(ch == '-') op = 1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
if(op) x = -x;
}
template <typename T, typename... Args> void Read(T &t, Args &... args) { Read(t); Read(args...); }
template <typename Temp> Temp Max(Temp x, Temp y) { return x > y ? x : y; }
template <typename Temp> Temp Min(Temp x, Temp y) { return x < y ? x : y; }
template <typename Temp> Temp Abs(Temp x) { return x < 0 ? (-x) : x; }
template <typename Temp> void Swap(Temp &x, Temp &y) { x ^= y ^= x ^= y; }
}
using namespace Quick_Function;
const int MAXN = 1e5 + 5;
int a[MAXN], n;
int pre[MAXN], p[MAXN];
bool vis[MAXN];
int cnt, ans = 1;
int dp[MAXN];
set<int> prime;
void Primes() {
vis[1] = 1;
for(int i = 2; i <= 100000; i++) {
if(!vis[i]) { p[++cnt] = i, pre[i] = i; }
for(int j = 1; j <= cnt && i * p[j] <= 100000; j++) {
vis[i * p[j]] = 1; pre[i * p[j]] = p[j];
if(i % p[j] == 0) break;
}
}
}
void Break_Down(int x) {
if(x == 1) return;
prime.insert(pre[x]);
Break_Down(x / pre[x]);
}
int main() {
Primes();
Read(n);
for(int i = 1; i <= n; i++) Read(a[i]);
sort(a + 1, a + 1 + n);
int m = unique(a + 1, a + 1 + n) - a - 1;
for(int i = 1; i <= m; i++) {
int maxn = 0;
Break_Down(a[i]);
for(set<int>::iterator it = prime.begin(); it != prime.end(); it++) maxn = Max(maxn, dp[*it] + 1);
for(set<int>::iterator it = prime.begin(); it != prime.end(); it++) dp[*it] = maxn;
prime.clear();
}
for(int i = 1; i <= 100000; i++) ans = Max(ans, dp[i]);
printf("%d", ans);
return 0;
}