题意:有三种不同颜色的珍珠(pearls)白(W颗),灰(G颗),黑(B颗), 其中3<=W+G+B<=40,问用这些珍珠可以串成多少种(W+G+B)长的不同的项链(项链可在平面内转动,也可翻转)。
令W+G+B=N;
先考虑转动,项链可转动(2PI)*K/N (1<=K<=N)共N个不同角度,而K置换(转动 (2PI)*K/N 度)可表示为 gcd(K,N)个长度为 N/gcd(K,N)的循环节,很容易发现如果gcd(W,G,B)%gcd(K,N)!=0,那么K置换的固定构型为0个,如果 gcd(W,G,B)%gcd(K,N)==0 那么 K置换的固定构型为 W/gcd(K,N), G/gcd(K,N),B/gcd(K,N)三类型的序列排列个数,即K置换的固定构型数为:C[F[W+G+B],F[W]] * C[F[G+B],B](另F[X]=X/gcd(K,N),X={W,G,B,X+X} , C[X,Y]为组合数)。
现在考虑翻转。
如果N为奇数,那么翻转的 N个置换都是{一个长度为1的循环节+(N-1)/2个长度为2的循环节},这样如果 W,G,B三个都为奇数,那么固定构型数为0,如果只有一个为奇数(假设W为奇数)那么固定构型数为 (W-1)/2, G/2,B/2的三类型序列排列个数。
如果N为偶数,那么有 N/2个置换为{N/2个长度为2的循环节},这种情况必须W,G,B都为偶数,而且很好处理。
还有N/2个置换为{(N-2)/2个长度为2的循环节,2个长度为1的循环节},如果W,G,B都是偶数,那么固定构型数为 {(W>=2)*{(W-2)/2,G/2,B/2 的三类型排列数} + (B>=2)*{W/2,G/2,(B-2)/2的三类型排列数} + (G>=2)*{W/2,(G-2)/2,G/2的三类型排列数}},如果W,G,B有两个是奇数(假设为W,G),那么固定构型数为2*{(W-1)/2,(G-1)/2,B的三类型排列数}。
由于其中涉及到的三类型排列数最大为 40!/14!/13!/13! = 2.4~* 10^17, 而max(unsigned long long )=2^64-1=1.8~*10^19 ,所以用unsigned long long 即可解决。
令W+G+B=N;
先考虑转动,项链可转动(2PI)*K/N (1<=K<=N)共N个不同角度,而K置换(转动 (2PI)*K/N 度)可表示为 gcd(K,N)个长度为 N/gcd(K,N)的循环节,很容易发现如果gcd(W,G,B)%gcd(K,N)!=0,那么K置换的固定构型为0个,如果 gcd(W,G,B)%gcd(K,N)==0 那么 K置换的固定构型为 W/gcd(K,N), G/gcd(K,N),B/gcd(K,N)三类型的序列排列个数,即K置换的固定构型数为:C[F[W+G+B],F[W]] * C[F[G+B],B](另F[X]=X/gcd(K,N),X={W,G,B,X+X} , C[X,Y]为组合数)。
现在考虑翻转。
如果N为奇数,那么翻转的 N个置换都是{一个长度为1的循环节+(N-1)/2个长度为2的循环节},这样如果 W,G,B三个都为奇数,那么固定构型数为0,如果只有一个为奇数(假设W为奇数)那么固定构型数为 (W-1)/2, G/2,B/2的三类型序列排列个数。
如果N为偶数,那么有 N/2个置换为{N/2个长度为2的循环节},这种情况必须W,G,B都为偶数,而且很好处理。
还有N/2个置换为{(N-2)/2个长度为2的循环节,2个长度为1的循环节},如果W,G,B都是偶数,那么固定构型数为 {(W>=2)*{(W-2)/2,G/2,B/2 的三类型排列数} + (B>=2)*{W/2,G/2,(B-2)/2的三类型排列数} + (G>=2)*{W/2,(G-2)/2,G/2的三类型排列数}},如果W,G,B有两个是奇数(假设为W,G),那么固定构型数为2*{(W-1)/2,(G-1)/2,B的三类型排列数}。
由于其中涉及到的三类型排列数最大为 40!/14!/13!/13! = 2.4~* 10^17, 而max(unsigned long long )=2^64-1=1.8~*10^19 ,所以用unsigned long long 即可解决。
1
#include <iostream>
2 #include <cstdio>
3 #include <cstring>
4
5 using namespace std;
6
7 const int max_n=41;
8 typedef unsigned long long ULL;
9
10 ULL c[max_n][max_n];
11
12 void ini(){
13 c[0][0]=1;
14 for ( int i=1;i<max_n;i++){
15 for ( int j=0;j<=i;j++){
16 if (j==0||j==i) c[i][j]=1;
17 else {
18 c[i][j]=c[i-1][j-1]+c[i-1][j];
19 }
20 }
21 }
22 }
23
24 int W,B,G,N;
25 int phi[max_n];
26
27 void gen_phi( int N){
28 int i,j;
29 phi[1]=1;
30 for (i=2;i<=N;i++) phi[i]=i;
31 for (i=2;i<=N;i+=2) phi[i]/=2;
32 for (i=3;i<=N;i+=2){
33 if (phi[i]==i){
34 for (j=i;j<=N;j+=i){
35 phi[j]=phi[j]/i*(i-1);
36 }
37 }
38 }
39 }
40 int gcd( int a, int b){
41 if (b==0) return a;
42 return gcd(b,a%b);
43 }
44
45 int main()
46 {
47 int T;
48 ini();
49 gen_phi(max_n-1);
50
51 scanf("%d",&T);
52 for ( int ncas=1;ncas<=T;ncas++){
53 scanf("%d%d%d",&W,&B,&G);
54 N=W+B+G;
55
56 ULL ans=0;
57
58 int e=gcd(W,B); e=gcd(e,G); //e为最小单元
59
60 for ( int i=1;i*i<=N;i++){
61 if (N%i==0){
62 if (i*i==N && (e%i==0) ){
63 ans += phi[i]*c[N/i][W/i]*c[(B+G)/i][B/i];
64 } else {
65 if (e%(i)==0){
66 ans += phi[i]*c[N/i][W/i]*c[(B+G)/i][B/i];
67 }
68 if (e%(N/i)==0){
69 int t=N/i;
70 ans += phi[t]*c[N/t][W/t]*c[(B+G)/t][B/t];
71 }
72 }
73 }
74 }
75
76 ULL part1=ans/N; ans=0;
77
78 int odd_cnt=(W&1)+(B&1)+(G&1);
79 if (N&1){ // 奇数个可分成一个长度为1的循环节和(N-1)/2个长度为2的循环节。
80 if (odd_cnt==1){
81 int T=N-1;
82 if (W&1){
83 ans += c[T/2][(W-1)/2]*c[(B+G)/2][B/2]*N;
84 } else if (B&1){
85 ans += c[T/2][(B-1)/2]*c[(W+G)/2][W/2]*N;
86 } else if (G&1){
87 ans += c[T/2][(G-1)/2]*c[(W+B)/2][W/2]*N;
88 }
89 }
90 } else {
91
92 if (odd_cnt==0){
93 ans += N/2*c[N/2][W/2]*c[(B+G)/2][B/2];
94 int T=N-2;
95 if (W>=2){
96 ans += N/2*c[T/2][(W-2)/2]*c[(B+G)/2][B/2];
97 }
98 if (B>=2){
99 ans += N/2*c[T/2][(B-2)/2]*c[(W+G)/2][W/2];
100 }
101 if (G>=2){
102 ans += N/2*c[T/2][(G-2)/2]*c[(W+B)/2][W/2];
103 //因为这个地方笔误,又再找各种莫须有的错误,让无聊的WA很嚣张的绽放了3次
104 //另又改成JAVA,提交Runtime Error 才发现。
105 }
106 }
107 if (odd_cnt==2){
108 int T=N-2;
109 if (!(W&1)){
110 ans += N*c[T/2][W/2]*c[(B+G-2)/2][(B-1)/2];
111 } else if (!(B&1)){
112 ans += N*c[T/2][B/2]*c[(W+G-2)/2][(G-1)/2];
113 } else if (!(G&1)){
114 ans += N*c[T/2][G/2]*c[(W+B-2)/2][(W-1)/2];
115 }
116 }
117 }
118 ans/=N;
119 ans=(ans+part1)/2;
120 printf("%llu\n",ans);
121 }
122 return 0;
123 }
124
2 #include <cstdio>
3 #include <cstring>
4
5 using namespace std;
6
7 const int max_n=41;
8 typedef unsigned long long ULL;
9
10 ULL c[max_n][max_n];
11
12 void ini(){
13 c[0][0]=1;
14 for ( int i=1;i<max_n;i++){
15 for ( int j=0;j<=i;j++){
16 if (j==0||j==i) c[i][j]=1;
17 else {
18 c[i][j]=c[i-1][j-1]+c[i-1][j];
19 }
20 }
21 }
22 }
23
24 int W,B,G,N;
25 int phi[max_n];
26
27 void gen_phi( int N){
28 int i,j;
29 phi[1]=1;
30 for (i=2;i<=N;i++) phi[i]=i;
31 for (i=2;i<=N;i+=2) phi[i]/=2;
32 for (i=3;i<=N;i+=2){
33 if (phi[i]==i){
34 for (j=i;j<=N;j+=i){
35 phi[j]=phi[j]/i*(i-1);
36 }
37 }
38 }
39 }
40 int gcd( int a, int b){
41 if (b==0) return a;
42 return gcd(b,a%b);
43 }
44
45 int main()
46 {
47 int T;
48 ini();
49 gen_phi(max_n-1);
50
51 scanf("%d",&T);
52 for ( int ncas=1;ncas<=T;ncas++){
53 scanf("%d%d%d",&W,&B,&G);
54 N=W+B+G;
55
56 ULL ans=0;
57
58 int e=gcd(W,B); e=gcd(e,G); //e为最小单元
59
60 for ( int i=1;i*i<=N;i++){
61 if (N%i==0){
62 if (i*i==N && (e%i==0) ){
63 ans += phi[i]*c[N/i][W/i]*c[(B+G)/i][B/i];
64 } else {
65 if (e%(i)==0){
66 ans += phi[i]*c[N/i][W/i]*c[(B+G)/i][B/i];
67 }
68 if (e%(N/i)==0){
69 int t=N/i;
70 ans += phi[t]*c[N/t][W/t]*c[(B+G)/t][B/t];
71 }
72 }
73 }
74 }
75
76 ULL part1=ans/N; ans=0;
77
78 int odd_cnt=(W&1)+(B&1)+(G&1);
79 if (N&1){ // 奇数个可分成一个长度为1的循环节和(N-1)/2个长度为2的循环节。
80 if (odd_cnt==1){
81 int T=N-1;
82 if (W&1){
83 ans += c[T/2][(W-1)/2]*c[(B+G)/2][B/2]*N;
84 } else if (B&1){
85 ans += c[T/2][(B-1)/2]*c[(W+G)/2][W/2]*N;
86 } else if (G&1){
87 ans += c[T/2][(G-1)/2]*c[(W+B)/2][W/2]*N;
88 }
89 }
90 } else {
91
92 if (odd_cnt==0){
93 ans += N/2*c[N/2][W/2]*c[(B+G)/2][B/2];
94 int T=N-2;
95 if (W>=2){
96 ans += N/2*c[T/2][(W-2)/2]*c[(B+G)/2][B/2];
97 }
98 if (B>=2){
99 ans += N/2*c[T/2][(B-2)/2]*c[(W+G)/2][W/2];
100 }
101 if (G>=2){
102 ans += N/2*c[T/2][(G-2)/2]*c[(W+B)/2][W/2];
103 //因为这个地方笔误,又再找各种莫须有的错误,让无聊的WA很嚣张的绽放了3次
104 //另又改成JAVA,提交Runtime Error 才发现。
105 }
106 }
107 if (odd_cnt==2){
108 int T=N-2;
109 if (!(W&1)){
110 ans += N*c[T/2][W/2]*c[(B+G-2)/2][(B-1)/2];
111 } else if (!(B&1)){
112 ans += N*c[T/2][B/2]*c[(W+G-2)/2][(G-1)/2];
113 } else if (!(G&1)){
114 ans += N*c[T/2][G/2]*c[(W+B-2)/2][(W-1)/2];
115 }
116 }
117 }
118 ans/=N;
119 ans=(ans+part1)/2;
120 printf("%llu\n",ans);
121 }
122 return 0;
123 }
124