【CF980D】Perfect Groups(仔细一想是道水题)

点此看题面

  • 给定一个长度为(n)的序列。
  • 定义一个序列的值为最少要划分多少组,使得每组的数两两乘积都是平方数。
  • 现在要对于每个(kin[1,n]),求出这个序列有多少值为(k)的子串。
  • (nle5000)

解题思路

重要的事情放前面:注意特殊处理(0)的情况,因为(0)可以贴到任意一组里面!

然后考虑不为(0)的情况,我们先去掉(a_i)的全部平方因子,然后就发现两数乘积为平方数只可能是这两数相同。

也就是只有相同的数才能并到一组,而既然要求最小组数,则相同的数必然并到一组,因此只要求有多少不同的数即可。

直接暴枚所有子串就做完了。

代码:(O(n^2))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 5000
using namespace std;
int n,a[N+5],dc,dv[N+5],s[N+5],vis[N+5];
int main()
{
	RI i,j;for(scanf("%d",&n),i=1;i<=n;dv[i]=a[i],++i)
		for(scanf("%d",a+i),j=2;j*j<=abs(a[i]);++j) W(!(a[i]%(j*j))) a[i]/=j*j;//除去所有平方因子
	sort(dv+1,dv+n+1),dc=unique(dv+1,dv+n+1)-dv-1;//排序去重
	for(i=1;i<=n;++i) a[i]=lower_bound(dv+1,dv+dc+1,a[i])-dv;//离散化
	RI t;for(i=1;i<=n;++i) for(t=0,j=i;j<=n;++j)//暴枚子串
		dv[a[j]]&&vis[a[j]]^i&&(vis[a[j]]=i,++t),++s[max(t,1)];//统计有多少不同的数(0除外),但注意全是0也得有一组
	for(i=1;i<=n;++i) printf("%d%c",s[i]," 
"[i==n]);return 0;//输出答案
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF980D.html