zoukankan      html  css  js  c++  java
  • NOIP 模拟 $88; m 对弈$

    题解 (by;zjvarphi)

    可以发现,(Alice) 的最优决策是能往左就往左,而 (Bob) 相反,所以设 (d_i=b_i-a_i-1),每堆石子的个数是 (n_i)

    题意转化:每次 (d_i) 都只减不增,所以可以看为有 (frac{k}{2}) 堆石子,每次可以至多从 (m) 堆石子中选,至少从被选的每堆中各挑一个,若当前的人没有可选的,那么当前人输。

    一个定理:先手必败当且仅当所有 (n_i) 在二进制下,每一个二进制 (1) 的个数 (mod m+1=0)

    (f_{i,j}) 表示:考虑了前 (i) 个二进制位,一共有 (j) 个石子,先手必败的方案数。

    转移的时候枚举当前二进制位选了多少个,再乘上个组合数就行。

    最后总方案数就是 (inom{n-frac{k}{2}-i}{frac{k}{2}} imes inom{i+frac{k}{2}-1}{frac{k}{2}-1})

    解释一下:

    前一个式子表示当前一共占了 (k+i) 个位置,剩下的位置被石子分成了 (frac{k}{2}+1) 堆的方案数,因为每堆可以为 (0),所以总数加上 (frac{k}{2}+1),最后由鸽巢原理可得前式。

    后一个式子就是分给每堆多少个石子,同样可以为空。

    Code
    #include<bits/stdc++.h>
    #define ri signed
    #define pd(i) ++i
    #define bq(i) --i
    #define func(x) std::function<x>
    namespace IO{
        char buf[1<<21],*p1=buf,*p2=buf;
        #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
        #define debug1(x) std::cerr << #x"=" << x << ' '
        #define debug2(x) std::cerr << #x"=" << x << std::endl
        #define Debug(x) assert(x)
        struct nanfeng_stream{
            template<typename T>inline nanfeng_stream &operator>>(T &x) {
                bool f=false;x=0;char ch=gc();
                while(!isdigit(ch)) f|=ch=='-',ch=gc();
                while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
                return x=f?-x:x,*this;
            }
        }cin;
    }
    using IO::cin;
    namespace nanfeng{
        #define FI FILE *IN
        #define FO FILE *OUT
        template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
        template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
        using ll=long long;
        static const int N=1e4+7,MOD=1e9+7;
        int f[22][N],frac[N],inv[N],n,k,m,lim;
        ll ans;
        auto fpow=[](int x,int y) {
            int res=1;
            while(y) {
                if (y&1) res=1ll*res*x%MOD;
                x=1ll*x*x%MOD;
                y>>=1;
            }
            return res;
        };
        auto C=[](int n,int m) {return 1ll*frac[n]*inv[m]%MOD*inv[n-m]%MOD;};
        inline int main() {
            FI=freopen("chess.in","r",stdin);
            FO=freopen("chess.out","w",stdout);
            cin >> n >> k >> m;
            lim=k>>1;
            frac[0]=inv[0]=1;
            for (ri i(1);i<=n;pd(i)) frac[i]=1ll*frac[i-1]*i%MOD;
            inv[n]=fpow(frac[n],MOD-2);
            for (ri i(n-1);i;bq(i)) inv[i]=1ll*inv[i+1]*(i+1)%MOD;
            f[0][0]=1;
            for (ri i(0);i<20;pd(i))
                for (ri j(0);j<=n-k;pd(j))
                    for (ll l(0);j+(l<<i)<=n-k&&l<=lim;l+=m+1) {
                        (f[i+1][j+(l<<i)]+=C(lim,l)*f[i][j]%MOD)%=MOD;
                    }
            for (ri i(0);i<=n-k;pd(i))
                ans+=1ll*C(n-lim-i,lim)*(C(i+lim-1,lim-1)-f[20][i])%MOD;
            printf("%lld
    ",(ans%MOD+MOD)%MOD);
            return 0;
        }
    }
    int main() {return nanfeng::main();}
    
  • 相关阅读:
    公用技术——设计模式23——访问者模式——待补充
    公用技术——设计模式24——空对象模式——待补充
    数据库语言——SQL——基础部分——初篇
    短信通道——阿里大鱼(java)
    spring cloud的常见注解
    HashMap在Jdk1.7和1.8中的实现
    java基础面试题
    java当中需要进一步学习的内容
    jsp中9大内置对象
    mysql中的锁
  • 原文地址:https://www.cnblogs.com/nanfeng-blog/p/15501007.html
Copyright © 2011-2022 走看看