BZOJ1547 周末晚会
2016-07-07 11:56
337 查看
模是1e8+7啊卧槽真tm蛋疼……
因为题里要求循环同构的算同一种,所以我们考虑一下burnside,置换一共有n个,分别是往后窜1~n个位置
对于窜x个位置的置换,一共有gcd(n,x)个循环节,且第i个位置属于第i%(gcd(n,x))+1个循环节
那么对于一个窜x个位置的置换,合法的不动点数量就是长度为gcd(n,x)的环,不考虑循环同构,没有超过k个女生坐在一起的方案数
如果gcd(n,x)<=k,那么如果k<n,合法方案数为2^gcd(n,x)-1,如果k>=n,合法方案数为2^gcd(n,x)
否则
用f[i][j]表示长度为i的线段(不是环),最后有且仅有j个女生,没有超过k个女生坐在一起的方案数
F[i][j]表示长度为i的线段,最后有且仅有j个女生,且第一个是男生,没有超过k个女生坐在一起的方案数
简单n^2递推
那么长度为i的环的方案就是长度为i的线段的方案数减去两边接起来超过k个了的方案数
枚举两边的女生个数和简单算一下即可
因为题里要求循环同构的算同一种,所以我们考虑一下burnside,置换一共有n个,分别是往后窜1~n个位置
对于窜x个位置的置换,一共有gcd(n,x)个循环节,且第i个位置属于第i%(gcd(n,x))+1个循环节
那么对于一个窜x个位置的置换,合法的不动点数量就是长度为gcd(n,x)的环,不考虑循环同构,没有超过k个女生坐在一起的方案数
如果gcd(n,x)<=k,那么如果k<n,合法方案数为2^gcd(n,x)-1,如果k>=n,合法方案数为2^gcd(n,x)
否则
用f[i][j]表示长度为i的线段(不是环),最后有且仅有j个女生,没有超过k个女生坐在一起的方案数
F[i][j]表示长度为i的线段,最后有且仅有j个女生,且第一个是男生,没有超过k个女生坐在一起的方案数
简单n^2递推
那么长度为i的环的方案就是长度为i的线段的方案数减去两边接起来超过k个了的方案数
枚举两边的女生个数和简单算一下即可
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<iomanip> #include<queue> #include<map> #include<bitset> #include<stack> #include<vector> #include<set> using namespace std; #define MAXN 2010 #define MAXM 1010 #define INF 1000000000 #define MOD 100000007 #define ll long long #define eps 1e-8 int n,k; int mi[MAXN]; int f[MAXN][MAXN],F[MAXN][MAXN],S[MAXN],s[MAXN],g[MAXN]; int gcd(int x,int y){ return !y?x:gcd(y,x%y); } ll MI(ll x,ll y){ ll re=1; while(y){ if(y&1){ (re*=x)%=MOD; } (x*=x)%=MOD; y>>=1; } return re; } int main(){ int i,j; int tmp; mi[0]=1; for(i=1;i<=2000;i++){ mi[i]=(mi[i-1]<<1)%MOD; } scanf("%d",&tmp); while(tmp--){ scanf("%d%d",&n,&k); if(k>n){ k=n; } f[0][0]=s[0]=1; F[0][0]=S[0]=1; F[1][0]=S[1]=1; for(i=2;i<=n;i++){ F[i][0]=S[i-1]; S[i]=F[i][0]; for(j=1;j<=k;j++){ F[i][j]=F[i-1][j-1]; (S[i]+=F[i][j])%=MOD; } } for(i=1;i<=n;i++){ f[i][0]=s[i-1]; s[i]=f[i][0]; for(j=1;j<=k;j++){ f[i][j]=f[i-1][j-1]; (s[i]+=f[i][j])%=MOD; } g[i]=s[i]; for(j=k+1;j<=min(2*k,i-1);j++){ (g[i]+=MOD-(ll)F[i-j][0]*max(0,min(k,j-1)-max(1,j-k)+1)%MOD)%=MOD; } } ll ans=0; for(i=1;i<=n;i++){ int l=gcd(i,n); if(l<=k){ if(k<n){ (ans+=mi[l]-1+MOD)%=MOD; }else{ (ans+=mi[l])%=MOD; } }else{ (ans+=g[l])%=MOD; } } (ans*=MI(n,MOD-2))%=MOD; printf("%lld\n",ans); } return 0; } /* 1 9 8 */
相关文章推荐
- Android支付宝和微信支付集成
- javascript zero to hero系列(1 开篇)
- 模板方法模式
- Android 自定义View (三) 圆环交替 等待效果
- (C)非局部跳转语句(setjmp和longjmp)
- iOS学习之WebView的使用
- Apache的虚拟目录功能介绍
- 如何在sublime text 中设置快捷键 运行浏览器
- error while loading shared libraries: xxx.so.x"错误的原因和解决办法
- SpringMVC Json格式输出
- xcode官方版本离线下载
- spring boot 内嵌数据库
- 敏捷团队转型之差距分析
- 垂直滚动公告(垂直跑马灯)
- WinForm遍历窗体所有子控件的方法
- Jrebel 6 license server激活方法
- Spring开发中的异常处理
- apache commons fileupload 下载(2016-07-01更新)
- NodeMCU教程 http请求获取Json中文乱码解决方案
- smb中文乱码编码解决