He‘s Circles
He wrote n letters "X" and "E" in a circle. He thought that there were 2n possibilities to do it, because each letter may be either "X" or "E". But Qc noticed that some different sequences of letters can be transformed one to another with a circular shift (thus representing actually the same circular string).
For example, strings "XXE"-"XEX"-"EXX" are actually the same.
Qc wants to know how many different circular strings of n letters exist. Help him to find that out.
Input
The input file contains a single integer 1 <= n <= 200000.
Output
Output a single integer --- the number circular strings of length n.
Sample Input
Sample test(s)
Input
Test #1
3
Test #2
4
Output
Test #1
4
Test #2
6
这道题是等价类计数问题。
由于是我写的第一题,我会把过程写的尽量详细,用以纪念。
题意:有一个长度为N的环,上面写着’X’和’E’,问本质不同的环有多少种。(N不超过200000)。
考虑用Pólya定理,答案是Σ(每个置换的不动点个数)/n,如何求不动点个数?这里枚举所有置换,假设当前枚举到的置换为"循环移动k位",d=(n,k),若1位置在当前置换下可以到3位置,则1位置和3位置处在同一循环,这时循环的个数就是d(每个循环经过n*k/d个点,由于每个间距为k,所以一个循环有n/d个点,那么就有d个循环),这对答案的贡献就是2^d(每个循环中随意涂色,不影响其为不动点),所以就可以枚举d,这时我们可以知道与n的GCD为d的数有φ(n/d)个,那么这里答案则为1/n*Σ2^d*φ(n/d)。
然后还要用高精度,真羡慕JAVA。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=200010; 6 int n,tot; 7 int phi[maxn],pri[maxn]; 8 9 void Linear_Shaker(){ 10 phi[1]=1; 11 for(int i=2;i<=n;i++){ 12 if(!phi[i]){ 13 phi[i]=i-1; 14 pri[++tot]=i; 15 } 16 for(int j=1;j<=n;j++){ 17 if(i*pri[j]>n)break; 18 if(i%pri[j]!=0) 19 phi[i*pri[j]]=phi[i]*(pri[j]-1); 20 else{ 21 phi[i*pri[j]]=phi[i]*pri[j]; 22 break; 23 } 24 } 25 } 26 } 27 28 int POW[4]={1,10,100,1000}; 29 const int mod=10000; 30 struct ExtInt{ 31 int num[20010],len; 32 ExtInt(int x){len=0; 33 memset(num,0,sizeof(num)); 34 do{ 35 num[++len]=x%mod; 36 x/=mod; 37 }while(x); 38 } 39 40 void Scf(){ 41 char s[10010];scanf("%s",s+1); 42 memset(num,0,sizeof(num));len=1; 43 for(int i=strlen(s+1),cnt=0;i>=1;i--){ 44 num[len]+=POW[cnt++]*(s[i]-‘0‘); 45 if(cnt==4)cnt=0,len+=1; 46 } 47 } 48 49 int operator [](int x){ 50 return num[x]; 51 } 52 53 void Prf(){ 54 printf("%d",num[len]); 55 for(int i=len-1;i>=1;i--) 56 printf("%04d",num[i]); 57 printf("\n"); 58 } 59 }; 60 61 ExtInt operator +(ExtInt a,int b){ 62 ExtInt ret(0); 63 ret.len=a.len; 64 for(int i=1,in=0;i<=ret.len||in;i++){ 65 ret.num[i]=a[i]+b+in;in=ret[i]/mod; 66 ret.num[i]%=mod;ret.len=max(ret.len,i); 67 } 68 return ret; 69 } 70 71 ExtInt operator +(ExtInt a,ExtInt b){ 72 ExtInt ret(0); 73 ret.len=max(a.len,b.len); 74 for(int i=1,in=0;i<=ret.len||in;i++){ 75 ret.num[i]=a[i]+b[i]+in;in=ret[i]/mod; 76 ret.num[i]%=mod;ret.len=max(ret.len,i); 77 } 78 return ret; 79 } 80 81 ExtInt operator *(ExtInt a,ExtInt b){ 82 ExtInt ret(0); 83 for(int i=1;i<=a.len;i++){ 84 for(int j=1,in=0;j<=b.len||in;j++){ 85 ret.num[i+j-1]+=a[i]*b[j]+in;in=ret[i+j-1]/mod; 86 ret.num[i+j-1]%=mod;ret.len=max(ret.len,i+j-1); 87 } 88 while(!ret[ret.len]) 89 ret.num[ret.len--]=0; 90 ret.len=max(ret.len,1); 91 } 92 return ret; 93 } 94 95 ExtInt operator ^(ExtInt a,int k){ 96 ExtInt ret(1); 97 while(k){ 98 if(k&1)ret=ret*a; 99 k>>=1;a=a*a; 100 } 101 return ret; 102 } 103 104 ExtInt operator /(ExtInt a,int k){ 105 for(int i=a.len,tot=0;i>=1;i--){ 106 tot=tot*10000+a[i]; 107 a.num[i]=tot/k; 108 tot%=k; 109 } 110 while(!a[a.len]) 111 a.num[a.len--]=0; 112 return a; 113 } 114 115 int GCD(int a,int b){ 116 return b?GCD(b,a%b):a; 117 } 118 119 int main(){ 120 scanf("%d",&n); 121 Linear_Shaker(); 122 ExtInt ans(0); 123 for(int d=1;d<=n;d++) 124 if(n%d==0){ 125 ExtInt x(2); 126 ans=ans+(x^d)*phi[n/d]; 127 } 128 ans=ans/n; 129 ans.Prf(); 130 return 0; 131 }
数学计数原理(Pólya,高精度):SGU 294 He's Circles