• 多校赛 count


    我们爱数数 (counting) TankEngineer 是数数高手,每天早上的乐趣是倒背圆周率。 TankEngineer 的家里有一张圆桌,每个位置按顺时针从 1 到 N 编号,差的绝对值为 1 的两个位置 相邻。特别的,编号为 N 的位置与编号为 1 的位置相邻。 他的家里某天来了 N 个人,编号从 1 到 N。如果编号为 i 的人坐到了编号为 i 的位置或坐到了与编 号为 i 的位置相邻的位置,这个人就会感到开心,反之这个人会感到沮丧。 于是 TankEngineer 想知道,有多少种安排坐位的方法,使所有人都入座,并且使得至少 K 个人开 心。 输入格式 第一行,包含两个整数 N, K。 输出格式 第一行,包含一个整数,表示合法方案的数量。因为数值太大,你只需要输出结果除以 (109 +7) 的 余数。 输入输出样例 输入 输出 4 4 9 样例解释 合法的方案有{1,2,3,4}, {1,2,4,3}, {1,3,2,4}, {2,1,3,4}, {2,1,4,3}, {2,3,4,1}, {4,1,2,3}, {4,2,3,1}, {4,3,2,1}这九种。 数据范围 • 对于 20% 的数据,3 ≤ K ≤ N ≤ 10。 • 对于另外 40% 的数据,3 ≤ K ≤ N ≤ 20。 • 对于 100% 的数据,3 ≤ K ≤ N ≤ 1,000。

    对其先dp,再容斥。

    //#pragma GCC optimize("-Ofast")
    #include<bits/stdc++.h>
    #define N 1007
    #define LL long long
    #define mo 1000000007
    #define pan(x) (x>1?x*2-4:x*2)
    #define rev(x) (x>1?(x&1)*2+1:(x&1)*2)
    using namespace std;
    LL fac[N],dp[2][4][4][N];
    int cnt,usd[7];
    void dfs(int x){
        if (x==4) {
            cnt=0;
            for (int i=0;i<=4;i++) cnt+=usd[i];
            dp[0][usd[0]*2+usd[1]][usd[3]*2+usd[4]][cnt]++;
            return;
        }
        dfs(x+1);
        for (int i=x-1;i<=x+1;i++) if (!usd[i]) {
            usd[i]=1; dfs(x+1); usd[i]=0;
        }
    }
    LL ans[N],anw;
    int last,now,sg,n,k;
    void Mo(LL &X){X<mo?0:X-=mo;}
    void Mo2(LL &X){X<0?X+=mo:0;}
    //namespace Lxf{
    //  int dp[2][1<<20|7][23];
    //  LL anw[21]={146326063,815973092,915753998,600280495,137677515,450305684,64421590,402761682,449445773,215161119,505685262,896311088,955416925,457272986,211789501,304437609,869722750,177100439,9159959,285649,15129};
    //  void bao() {
    //      if (n==20) {
    //          printf("%lld
    ",anw[k]); exit(0);}
    //      memset(dp,0,sizeof dp); ans=0;
    //      for (int i=3;i<n;i++) dp[0][1<<i-1][0]++;
    //      
    //      dp[0][1][1]=1; dp[0][2][1]=1; dp[0][1<<n-1][1]=1;
    //      int sta=(1<<n);
    //      for (int i=2;i<=n;i++) {
    //          last=i&1; now=1^last;
    //          memset(dp[now],0,sizeof dp[now]);
    //          for (int st=0;st<sta;st++) {
    //          for (int p=0;p<i;p++) {
    //           if (!dp[last][st][p]) continue; 
    //           for (int k=1;k<=n;k++) {
    //               if ((st>>k-1)&1) continue;
    //            if (abs(k-i)<2||(i==n&&k==1)) Mo(dp[now][st|(1<<k-1)][p+1]+=dp[last][st][p]);
    //            else  Mo(dp[now][st|(1<<k-1)][p]+=dp[last][st][p]);
    //          }
    //         }
    //        }
    //    }
    //    for (int st=0;st<sta;st++) 
    //     for (int p=k;p<=n;p++) 
    //      Mo(ans+=dp[now][st][p]);
    //    printf("%d",ans);//cerr<<ans<<endl;
    //    exit(0);
    //  }
    //}
    LL ni[N];
    LL qsm(LL x,LL y){
        static LL anw;
        for (anw=1;y;y>>=1,x=x*x%mo) if (y&1) anw=anw*x%mo;
        return anw;
    }
    LL C(int x,int y){
        return fac[x]*ni[y]%mo*ni[x-y]%mo;
    }
    signed main () {
        freopen("counting.in","r",stdin);
        freopen("counting.out","w",stdout);
        scanf("%d%d",&n,&k);
        fac[0]=1; 
        for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mo;
        ni[n]=qsm(fac[n],mo-2);
        for (int i=n;i  ;i--) ni[i-1]=ni[i]*i%mo;
        if (k==0) return printf("%lld
    ",fac[n]),0;
        dfs(1);
    //    for(int i = 0; i < 4; ++i) {
    //        for(int j = 0; j < 4; ++j)    
    //        printf("%d ", dp[0][i][j][3]);
    //        puts("");
    //    }
        for (int i=4;i<=n;i++) {
         last=i&1; now=1^last;
         memset(dp[now],0,sizeof dp[now]);    
          for (int ins=0;ins<i;ins++) {
            for (int st=0;st<4;st++) {
                for (int ed=0;ed<4;ed++) {
                   sg=pan(ed); 
                   if (ins==3) ;
                   if (!(ed&2))  (dp[now][st][sg  ][ins+1]+=dp[last][st][ed][ins])%=mo;
                   if (!(sg&2))  (dp[now][st][sg+2][ins+1]+=dp[last][st][ed][ins])%=mo;
                   if (!(sg&1))  (dp[now][st][sg+1][ins+1]+=dp[last][st][ed][ins])%=mo; 
                }
            }
          }
          for (int ins=0;ins<=i;ins++)
          for (int st=0;st<4;st++) {
            for (int ed=0;ed<4;ed++) 
              (dp[now][st][pan(ed)][ins]+=dp[last][st][ed][ins])%=mo;
          } 
        }
        
        for (int i=1;i<=n;i++) 
         for (int st=0;st<4;st++)
          for (int ed=0;ed<4;ed++) {
            if (ed&st) continue;
           Mo(ans[i]+=dp[now][st][ed][i]);
         }
        for (int i=n;i>=k;i--) {
         ans[i]=ans[i]*fac[n-i]%mo;
         for (int j=i+1;j<=n;j++) 
          ans[i]-=ans[j]*C(j,i)%mo,Mo2(ans[i]); 
          Mo(anw+=ans[i]);
        }
        printf("%lld
    ",anw); 
        return 0;
    }
  • 相关阅读:
    (Java随机数举例)随机扔一千次硬币的正反次数
    hibernate+spring的整合思路加实例(配图解)
    从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写
    ssh连接Linux自动断开后再也无法连上的问题
    面试题10:二进制中1的个数
    C 语言统计关键字出现次数
    在Eclipse中Attach Source
    Visual Sudio 2012转换界面风格
    java 判断字符串IP合法性以及获取IP的数值形式
    java.lang.string split 以点分割字符串无法正常拆分字符串
  • 原文地址:https://www.cnblogs.com/rrsb/p/9867301.html
Copyright © 2020-2023  润新知