MG loves string
Accepts: 30Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 262144/262144 K (Java/Others)问题描述MG是一个很忙碌的男孩子。今天他沉迷于这样一个问题: 对于一个长度为N的由小写英文字母构成的随机字符串,当它进行一次变换,所有字符i都会变成a[i]。 MG规定所有a[i]构成了26个字母组成的排列。 MG现在需要知道这个随机串变换到自身的期望变换次数。请你输出期望答案乘上26^n以后模 1000000007的结果。 MG认为这件事非常容易,不屑于用计算机解决,于是运用他高超的人类智慧开始进行计算。作为一名旁观者,你也想挑战MG智慧,请你写个程序,计算答案。
输入描述第一行一个整数T,代表数据组数(1 <=T<=10)。 接下来,对于每组数据—— 第一行一个整数N,表示给定的随机串长度(1<=N<=1000000000)。 第二行26个字母,表示a_i序列
输出描述对于每一组数据,输出一行。 显然,这个期望是一个实数。请你输出它乘上26^N以后模 1000000007 的结果
输入样例2 2 abcdefghijklmnpqrstuvwxyzo 1 abcdefghijklmnopqrstuvwxyz输出样例5956 26
【分析】
感觉BC的题挺好的啊【每次都能学到东西。。
首先,知道,这是个带LCM的期望。就是看随机串分别在长度为几的循环节里面,然后LCM。
然后,不同长度的循环节不会超过6个,1+2+3+4+5+6=21。
就是根据输入的那个串,只会有6种长度的循环节,所以你可以枚举真正的随机串涵盖的循环节有哪几个,枚举是2^6。
然后就是把n个字符放到那些循环节的字母集合中去,但是要保证每个循环节都一定有一个字母覆盖,问它的方案数。
其实这是经典的容斥原理,就是n个东西分到m个集合,让每个集合都至少有一个东西。
这里我们枚举子集就可以用容斥原理计算出来了【注意容斥,你要减掉的是没有涵盖某一个集合的,加上没有涵盖两个集合的。。。】
枚举子集是3^n(用二项式定理易证)
这个可以预处理的。
所以是$O(2^6*log(n)+3^6)$
官方题解:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Mod 1000000007 8 #define LL long long 9 10 int u[30],v[10],pp[10],n; 11 LL sm[1010]; 12 int h[1010],ss[1010],p[30]; 13 char s[30]; 14 bool vis[30]; 15 16 LL qpow(LL x,int b) 17 { 18 x%=Mod; 19 LL ans=1; 20 while(b) 21 { 22 if(b&1) ans=(ans*x)%Mod; 23 x=(x*x)%Mod; 24 b>>=1; 25 } 26 return ans; 27 } 28 29 void init() 30 { 31 memset(vis,0,sizeof(vis)); 32 memset(p,0,sizeof(p)); 33 memset(h,0,sizeof(h)); 34 memset(ss,0,sizeof(ss)); 35 scanf("%d",&n); 36 scanf("%s",s+1); 37 for(int i=1;i<=26;i++) u[i]=s[i]-'a'+1; 38 for(int i=1;i<=26;i++) if(!vis[i]) 39 { 40 vis[i]=1; 41 int x=i,cnt=1; 42 while(u[x]!=i) x=u[x],cnt++,vis[x]=1; 43 p[cnt]++; 44 } 45 v[0]=0; 46 for(int i=1;i<=26;i++) if(p[i]) v[++v[0]]=i,pp[v[0]]=p[i]; 47 for(int i=0;i<(1<<v[0]);i++) 48 for(int j=1;j<=6;j++) if(i&(1<<j-1)) ss[i]+=v[j]*pp[j],h[i]++; 49 for(int i=0;i<(1<<v[0]);i++) sm[i]=qpow(ss[i],n);sm[0]=0; 50 int i; 51 // for(i=0;i<(1<<v[0]);i++) 52 for(i=(1<<v[0])-1;i>=0;i--) 53 for(int j=i;j;j=(j-1)&i) 54 { 55 if(i==j) continue; 56 if((h[i]-h[j])%2==0) sm[i]+=sm[j]; 57 else sm[i]-=sm[j]; 58 sm[i]=(sm[i]%Mod+Mod)%Mod; 59 } 60 } 61 62 LL gcd(LL a,LL b) 63 { 64 if(b==0) return a; 65 return gcd(b,a%b); 66 } 67 68 LL ans; 69 70 void ffind(int x,int y,LL nw) 71 { 72 if(x==v[0]+1) 73 { 74 ans=(ans+sm[y]*nw)%Mod; 75 return; 76 } 77 ffind(x+1,y,nw); 78 ffind(x+1,y|(1<<x-1),nw*(LL)v[x]/gcd(nw,v[x])); 79 } 80 81 int main() 82 { 83 int T; 84 scanf("%d",&T); 85 while(T--) 86 { 87 init(); 88 ans=0;ffind(1,0,1); 89 printf("%lld ",ans); 90 } 91 return 0; 92 }
2017-04-02 10:41:18