codeforce 980D
题意:
已知有这么一道题:给你n个数字,你要将这n个数字打乱后分成k组,使得对于同一个组中的任意一对数字满足两个数相乘一定是个完全平方数,求出最小的k
而这道题的意思是:给你n个数字,这n个数字一共有(1+n)*n/2个连续子序列,对于连续每个子序列你都要求出上面的那个k,最后统计k=1的子序列有多少个,k=2的子序列有多少个……k=n的子序列有多少个
思路:
对于x(x!=0),如果存在一个y满足x是y²的倍数,那么将x变为x/y²不会影响答案
这样的话对于每个a[i],暴力所有平方数,如果整除就除掉,最后得到的a[i]必定满足 a[i] = ∏pj,其中pj各不相同且都为质数
结论:这样处理完之后,满足任意两个数相乘都为平方数的组内所有数字必定都相同,换句话说,只有相同的两个数相乘才能是个完全平方数,否则一定不是
这样这题就简单了:给你n个数字,这n个数字一共有(1+n)*n/2个连续子序列,对于每个连续子序列有多少个互不相同的数字,那么k就为多少
离散化暴力统计一下就ok了,复杂度O(n²)或O(n²logn)
当然要特判0!0乘任意一个数字都是0,所以0可以加入任何一个组中
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000;
int a[maxn];
int b[maxn];
int c[maxn];
int d[maxn];
int main ()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
//printf("111\n");
for(int i=1;i<=n;i++)
{
if(a[i]==0)
continue;
for(int j=2;j<=10000;j++)
{
while(a[i]%(j*j)==0)
a[i]=a[i]/(j*j);
}
}
//cout<<"111"<<endl;
//离散化
for(int i=1;i<=n;i++)
{
b[i]=a[i];
// cout<<b[i]<<endl;
}
sort(b+1,b+n+1);
int pos=unique(b+1,b+n+1)-(b+1);
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+pos+1,a[i])-(b);
}
// 处理0
int poss=lower_bound(b+1,b+pos+1,0)-(b);
if(b[poss])
poss=-1000;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
memset(d,0,sizeof(d));
int cnt=0;
for(int j=i;j<=n;j++)
{
if(a[j]!=poss&&d[a[j]]==0)
{
cnt++;
}
d[a[j]]=1;
c[max(cnt,1)]++;
}
}
for(int i=1;i<=n;i++)
printf("%d ",c[i]);
}