CF 980D Perfect Groups(数论)
一个数组a的子序列划分仅当这样是合法的:每个划分中的任意两个数乘积是完全平方数。定义a的权值为a的最小子序列划分个数。现在给出一个数组b,问权值为i的b的子串个数。
这题意真不是人类智慧能轻易描述的。据说此题在比赛场上读题30min,做题5min,做完还WA。果然是坑题。
如果有两个数a和b,a和b的乘积是完全平方数,那么如果a有因子x^2,那么x^2就可以去掉,使a变成a/x^2,结论依然成立。因此我们把所有数的质因子次数mod2,可以发现结论仍然不变。
因此,在一个划分内的数必须完全相同或者有数为零(涉及乘除法一定要考虑零啊啊啊)。n^2dp即可。
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=5005;
int n, a[maxn], b[maxn], cnt[maxn]; //cnt[i]储存i有几个
int k, ans[maxn], id0;
int deal(int x){
int flag;
if (x<0) x=-x, flag=-1; else flag=1;
for (int i=2; i*i<=x; ++i)
while (x%(i*i)==0) x/=i*i;
return x*flag;
}
int main(){
scanf("%d", &n); int t; id0=-1;
for (int i=1; i<=n; ++i){
scanf("%d", &t), a[i]=b[i]=deal(t);
if (!a[i]) id0=0;
}
sort(b+1, b+1+n);
if (!id0) id0=lower_bound(b+1, b+1+n, 0)-b;
for (int i=1; i<=n; ++i)
a[i]=lower_bound(b+1, b+1+n, a[i])-b;
for (int i=1; i<=n; ++i){
for (int j=1; j<=n; ++j) cnt[j]=0; k=0; //k:[i,j]不同元素的数目
for (int j=i; j<=n; ++j){
if (a[j]==id0){
if (!k) ++ans[1]; else ++ans[k];
continue;
}
if (!cnt[a[j]]) ++k;
++cnt[a[j]]; ++ans[k];
}
}
for (int i=1; i<=n; ++i) printf("%d ", ans[i]);
return 0;
}