题意:一个项链的珠子的颜色有若干种。每种颜色的珠子个数为Ai。求有多少种不同的项链?
我们考虑,如果旋转i个珠子,那么会产生gcd(n,i)个循环节,每个循环节的大小我们假设为K,那么如果有一个颜色的数量不是K的倍数,那么必然没有置换过后等价的情况,然而,如果全部都是K的倍数,那么我们就相当于在gcd(n,i)个空位里面,每种颜色放入a[i]/K个的方案总数,这是一个简单的组合计数问题,方法大概就是c(n,m1)*c(n-m1,m2)*c(n-m1-m2,m3)*... ...,然后还要再除以n,由于这题n高达1000,需要高精度,但是我比较懒,就没有打高精度的版本了。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int a[200005],n,m,p[200005]; 7 int gcd(int a,int b){ 8 if (b==0) return a; 9 else return gcd(b,a%b); 10 } 11 int C(int n,int m){ 12 int res=1; 13 for (int i=1;i<=n;i++) res*=i; 14 for (int i=1;i<=n-m;i++) res/=i; 15 for (int i=1;i<=m;i++) res/=i; 16 return res; 17 } 18 int main(){ 19 int T,ans; 20 scanf("%d",&T); 21 while (T--){ 22 scanf("%d",&m);n=0; 23 for (int i=1;i<=m;i++) {scanf("%d",&a[i]);n+=a[i];} 24 int ans=0; 25 for (int i=0;i<n;i++){ 26 int num=gcd(i,n); 27 int K=n/num,tot=0; 28 p[0]=0; 29 bool pd=1; 30 for (int j=1;j<=m&&pd;j++){ 31 if (a[j]%K){ 32 pd=0; 33 }else{ 34 p[++p[0]]=a[j]/K; 35 tot+=a[j]/K; 36 } 37 } 38 if (!pd) continue; 39 for (int j=1;j<=p[0];j++) 40 ans+=C(tot,p[j]),tot-=p[j]; 41 } 42 printf("%d ",ans/n); 43 } 44 }