原文链接https://www.cnblogs.com/zhouzhendong/p/9074164.html
题目传送门 - Codeforces 980D
题意
$ m Codeforces$ 真是个令人伤心的地方。
伤心的 $zzd$ 现在给你一个含有 $n$ 个数字元素的数列。
$zzd$ 问你对于 $1$ 到 $n$ 之间的每一个 $k$ 满足 $Q(序列)=k$ 的原序列的连续子序列个数。
其中,$Q()$定义如下:
把当前数列中的数分组,使得同组中任意两个数的乘积为完全平方数。其中最小分组数就是 $Q()$ 的值。
$nleq 5000,-10^8leq a_ileq 10^8$
题解
伤心的 $zzd$ 再一次来到了令人伤心的 $ m Codeforces $ ,再一次的看错题意,并再一次的没有考虑到坑点。
很容易发现对于一个数,它的平方因子对最后的分组没有影响。
我们把每一个数都除掉其最大平方因子,然后显然只有相同的数能分到同一组。
于是离散化一下 $O(n^2)$ 统计即可。
然后!!
有一个特殊的数字叫做 "0" !
$0$可以随便分组。
代码
#include <bits/stdc++.h> using namespace std; const int N=10005; int n,a[N],cnt=0; int pcnt=0,prime[N],f[N]; map <int,int> mp; int tot,v[N],ans[N]; void get_prime(int n){ for (int i=1;i<=n;i++) f[i]=1; f[1]=0; for (int i=2;i<=n;i++){ if (!f[i]) continue; prime[++pcnt]=i*i; for (int j=i*2;j<=n;j+=i) f[j]=0; } } int main(){ get_prime(10000); scanf("%d",&n); mp.clear(); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); if (a[i]==0) continue; for (int j=1;j<=pcnt;j++) while (a[i]%prime[j]==0) a[i]/=prime[j]; if (mp[a[i]]==0) mp[a[i]]=++cnt; a[i]=mp[a[i]]; } for (int i=1;i<=n;i++){ memset(v,0,sizeof v); tot=0; for (int j=i;j<=n;j++){ if (a[j]) tot+=v[a[j]]==0; v[a[j]]++; ans[max(tot,1)]++; } } for (int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }