CF980D Perfect Groups
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,c∈N+,
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,k∈N+
你可以理解成有传递性
证明可以用唯一分解定理:
那么说明我们可以将这些平方数用并查集维护在一个集合里,然后
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的主要内容,如果未能解决你的问题,请参考以下文章