[题解] 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;
}
posted @ 2021-04-17 15:34  Last_Breath  阅读(73)  评论(0编辑  收藏  举报