数论 集合? 集合!
wxy总是闲不住,有一天,他又给cc出难题,他的问题是这样的:给你n个数字的集合,n个数字有(n*(n+1))/2连续子区间,对于每个连续子区间,你需要将这个子区间的数分为尽量少的集合, 使得每个集合中任意两个数的乘积是完全平方数,(在对子区间进行划分时,不要求每个子区间内数在原集合中连续。)
第一行一个整数n,集合大小,(1<=n<=5000); 第二行n个整数a1,a2,…,an(-10^8≤ai≤10^8)
输出n个数 ,每个数表示可以划分的集合大小是i的总数(1<=i<=n);
思路
a*b为完全平方数,当且它们去掉所有偶数次方的质因子,剩下的数相同,注意一下a【i】=0.
因为数的大小为10的8次方,数组存不下,所以要离散化
#include <stdio.h> #include <math.h> #include<set> #include <string.h> #include <algorithm> using namespace std; const int maxn=500005; int a[maxn],b[maxn],c[maxn],vis[maxn]; int kabs(int x) { if(x<0) return -x; else return x; } int main() { int i,j,k,num,h,t,n,x,cnt; scanf("%d",&n); cnt=0; for(i=1; i<=n; i++) { scanf("%d",&a[i]); if(a[i]!=0) cnt++; } if(cnt==0) { printf("%d",n*(n+1)/2); for(i=2; i<=n; i++) printf(" 0"); printf("\n"); } else { for(i=1; i<=n; i++) { k=kabs(a[i]); for(j=2; j*j<=k; j++) { t=j*j; if(a[i]%t==0) { while(a[i]%t==0) { a[i]=a[i]/t; } } } } for(i=1; i<=n; i++) c[i]=a[i]; sort(c+1,c+n+1); int len=unique(c+1,c+n+1) - c; for(i=1; i<=n; i++) { if(a[i]==0) continue; a[i]=lower_bound(c+1,c+len+1,a[i]) - c; } memset(b,0,sizeof(b)); for(i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); num=0; for(j=i; j<=n; j++) { if(!vis[a[j]]&&a[j]!=0) { vis[a[j]]=1; num++; } if(num==0) b[num+1]++; else b[num]++; } } for(i=1;i<=n;i++) printf("%d ",b[i]); } return 0; }
Input | Output |
---|---|
2 |
3 0 |
5 |
5 5 3 2 0 |