博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

Codeforces.566F.Clique in the Divisibility Graph(DP)

题目链接

\(Description\)

给定集合\(S=\{a_1,a_2,\ldots,a_n\}\),集合中两点之间有边当且仅当\(a_i|a_j\)\(a_j|a_i\)
\(S\)最大的一个子集\(S'\),并满足\(S'\)中任意两点间都有连边(\(S'\)中只有1个点也是合法的)。
\(n,a_i\leq 10^6\)\(a_i\)互不相同。

\(Solution\)

从小到大选(已经排好序),如果选了\(a_i\),则下一个数一定是\(a_i\)的倍数,下下个数一定是下个数和这个数的倍数。。
容易想到DP,每次更新其倍数即可。

复杂度。。好像不是\(O(n\ln n)\)吧?哦,看漏了个\(a_i\)互不相同。。
\(a_i\)可相同就有趣了。
算了。。怎么着都能被卡到\(O(n^2)\)。。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=1e6+5;

int n,A[N],f[N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

int main()
{
	n=read(); int mx=0, ans=1;
	for(int i=1; i<=n; ++i) mx=std::max(mx,A[i]=read());
	for(int i=1; i<=n; ++i)
	{
		int a=A[i], v=++f[a];
		ans=std::max(ans,v);
		for(int j=a<<1; j<=mx; j+=a) f[j]=std::max(f[j],v);
	}
	printf("%d\n",ans);

	return 0;
}
posted @ 2018-08-29 20:07  SovietPower  阅读(248)  评论(0编辑  收藏  举报