zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    layui实现复选框全选,反选
    Lambda表达式详解
    母版页 VS shtml—ASP.NET细枝末节(3)
    无废话WCF入门教程一[什么是WCF]
    String.Format用法
    C#基础--之数据类型
    簡單SQL存儲過程實例
    SQL Server 存储过程
    存储过程详解
    sql语句分页多种方式ROW_NUMBER()OVER
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/8467451.html
Copyright © 2011-2022 走看看