1. 程式人生 > >bzoj1547 周末晚會

bzoj1547 周末晚會

math color sin ace pan 方案 algo aps stream

我們要求方案數,還是旋轉同構的,想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 }
View Code

bzoj1547 周末晚會