CF980D Perfect Groups

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF980D Perfect Groups相关的知识,希望对你有一定的参考价值。

CF980D Perfect Groups

题意:

将一个串划分为多个子集(不要求连续),要求同一子集内两任意元素的积为平方数

定义一个串的答案为所需的最少子集个数

一个长度为 n 的串有 n ( n + 1 ) 2 \\fracn(n+1)2 2n(n+1)个非空子串,求答案为 1 , 2 , 3 , ⋯   , n 1,2,3,\\cdots ,n 1,2,3,,n 的非空子串个数

题解:

这个不应该是紫题。。
先给结论:
如果 a , b , c ∈ N + a,b,c∈N^+ a,b,cN+, a b = n 2 ab=n^2 ab=n2, b c = m 2 bc=m^2 bc=m2,那么有 a c = k 2 ac=k^2 ac=k2 n , m , k ∈ N + n,m,k∈N^+ n,m,kN+
你可以理解成有传递性
证明可以用唯一分解定理:

那么说明我们可以将这些平方数用并查集维护在一个集合里,然后 n 2 n^2 n2枚举所有子串暴力统计

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
int n,x[5001],fa[5001],ans[5001],num[5001];
int find(int x)

	if(fa[x]==x)
		return x;
	return fa[x]=find(fa[x]);

void merge(int x,int y)

	fa[find(x)]=find(y);

signed main()

	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&x[i]);
		fa[i]=i;
	
		
	for(int i=1;i<=n;i++)
		for(int j=1;j<i;j++)
			if(x[i]*x[j]>0)
			
				int tmp=(int)sqrt(x[i]*x[j]);
				if(tmp*tmp==x[i]*x[j])
					merge(i,j);
			
			
	for(int i=1;i<=n;i++)
	
		int tot=0;
		memset(num,0,sizeof(num));
		for(int j=i;j<=n;j++)
			if(x[j]==0)
				ans[max(1ll,tot)]++;
			else
			
				if(!num[find(j)])
					num[find(j)]=1;
					tot++;
				
				ans[tot]++;
			
	
	for(int i=1;i<=n;i++)
		printf("%lld ",ans[i]);

以上是关于CF980D Perfect Groups的主要内容,如果未能解决你的问题,请参考以下文章

CF980D Perfect Groups

cf980d Perfect Groups

CF 980D Perfect Groups(数论)

CF980D Perfect Groups

Codeforces 980D Perfect Groups

cf round480D Perfect Groups