bzoj1547 周末晚会
我们要求方案数,还是旋转同构的,想burnside,如果我们能计算出转i位不变的满足条件的数量,那么这道题我们就解决了。
考虑转i位时,设tmp=gcd(i,n),那么就共有tmp个循环节。
当tmp<=k时,只要不是所有的循环节都是女生就可以,所以数量为2^tmp-1,但是要特判k>=n,因为这时所有方案都满足条件。
当tmp>k时,我们需要在提前处理出符合条件的且旋转不变的方案数,考虑dp,我们设f[i][j]表示长度为i的线段第一位是男生,末尾有且仅有j位女生的满足条件的方案,g[i][j]与f相同,只是不限首位。h[i]表示环的,就是线段的去掉首尾相加大与k的,这里注意中间的区间位置不唯一。
最后直接上burnside就好了!
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #define int long long 7 #define N 2050 8 #define mod 100000007 9 using namespace std; 10 int T,n,m,ans; 11 int f[N][N],g[N][N],h[N],s[N],pw[N]; 12 int qp(int a,int b){ 13 int c=1; 14 while(b){ 15 if(b&1)c=c*a%mod; 16 a=a*a%mod; b>>=1; 17 }return c; 18 } 19 int gcd(int a,int b){return !b?a:gcd(b,a%b);} 20 signed main(){ 21 scanf("%lld",&T); 22 pw[0]=1; 23 for(int i=1;i<=2000;i++)pw[i]=(pw[i-1]<<1)%mod; 24 while(T--){ 25 ans=0; 26 scanf("%lld%lld",&n,&m); 27 f[1][0]=s[1]=1;f[1][1]=0; 28 for(int i=2;i<=n;i++){ 29 f[i][0]=s[i]=s[i-1]; 30 for(int j=1;j<=m&&j<i;j++){ 31 f[i][j]=f[i-1][j-1]; 32 (s[i]+=f[i][j])%=mod; 33 } 34 } 35 g[0][0]=s[0]=1; 36 for(int i=1;i<=n;i++){ 37 g[i][0]=s[i]=s[i-1]; 38 for(int j=1;j<=m&&j<=i;j++){ 39 g[i][j]=g[i-1][j-1]; 40 (s[i]+=g[i][j])%=mod; 41 } 42 h[i]=s[i]; 43 for(int j=m+1;j<=2*m&&j<i;j++) 44 h[i]=(h[i]-(f[i-j][0]*max((int)0,min(j-1,m)-max((int)1,j-m)+(int)1))%mod+mod)%mod; 45 } 46 for(int i=1;i<=n;i++){ 47 int tmp=gcd(i,n); 48 if(tmp<=m){ 49 if(m>=n)ans=(ans+pw[tmp])%mod; 50 else ans=(ans+pw[tmp]-1+mod)%mod; 51 } 52 else ans=(ans+h[tmp])%mod; 53 } 54 ans=ans*qp(n,mod-2)%mod; 55 printf("%lld\n",ans); 56 } 57 return 0; 58 }
人生如梦亦如幻 朝如晨露暮如霞。