【CF980D】Perfect Groups(仔细一想是道水题)
- 给定一个长度为\(n\)的序列。
- 定义一个序列的值为最少要划分多少组,使得每组的数两两乘积都是平方数。
- 现在要对于每个\(k\in[1,n]\),求出这个序列有多少值为\(k\)的子串。
- \(n\le5000\)
解题思路
重要的事情放前面:注意特殊处理\(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]," \n"[i==n]);return 0;//输出答案
}
待到再迷茫时回头望,所有脚印会发出光芒