CF 980D Perfect Groups(数论)

CF 980D Perfect Groups(数论)

一个数组a的子序列划分仅当这样是合法的:每个划分中的任意两个数乘积是完全平方数。定义a的权值为a的最小子序列划分个数。现在给出一个数组b,问权值为i的b的子串个数。

这题意真不是人类智慧能轻易描述的。据说此题在比赛场上读题30min,做题5min,做完还WA。果然是坑题。

如果有两个数a和b,a和b的乘积是完全平方数,那么如果a有因子x2,那么x2就可以去掉,使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;
}
posted @ 2018-05-17 20:45  pechpo  阅读(301)  评论(0编辑  收藏  举报