• agc045_d Lamps and Buttons


    agc045_d Lamps and Buttons

    https://atcoder.jp/contests/agc045/tasks/agc045_d

    Snipaste_2020-06-29_17-59-23.png

    Tutorial

    考虑Snuke的策略.

    从小到大一次枚举 (i) ,按下 (i) ,如果 (p_i=i) ,则失败,否则可以点亮 (i) 所在的环.如果某次操作后所有灯都是亮的,则胜利,结束游戏.

    本质上的原因是,枚举 (i) 的顺序对于获胜的概率没有影响.

    所以,设 (t)([1,A]) 最小的位置使得 (p_t=t) (若不存在,则 (t=A+1)).那么获胜的条件就是,对于所有(i in [A+1,N]),存在(xin [1,t))使得(x)(i)所属环内.

    由于需要保证(t)的最小性,所以需要增加一步容斥.

    现在的问题相当于,要找到一个(a+b+c)的排列,满足对于(iin[a+1,a+b]),存在一个(xin[1,a])使得(x)(i)的环内

    [a! cdot dfrac {(a+b-1)!}{(a-1)!} cdot dfrac {(a+b+c)!}{(a+b)!} = (a+b+c)! cdot dfrac a{a+b} ]

    复杂度 (O(A^2+N))

    Code

    #include <cstdio>
    #include <iostream>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define inver(a) power(a,mod-2)
    #define upd(a,b) a=add(a+b)
    #define INV(a) ((ll)inv[a]*fac[a-1]%mod)
    using namespace std;
    inline char gc() {
    //	return getchar();
    	static char buf[100000],*l=buf,*r=buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void rd(T &x) {
    	x=0; int f=1,ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
    	x*=f;
    }
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=1e7+50;
    const int maxA=5000+5;
    int n,A;
    int fac[maxn],inv[maxn];
    inline int add(int x) {return x>=mod?x-mod:x;}
    inline int sub(int x) {return x<0?x+mod:x;}
    ll power(ll x,ll y) {
    	ll re=1;
    	while(y) {
    		if(y&1) re=re*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return re;
    }
    inline int binom(int x,int y) {
    	return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;
    }
    inline int cal(int a,int b,int c) {
    	return (ll)fac[a+b+c]*a%mod*INV(a+b)%mod;
    }
    void init(int n) {
    	fac[0]=1;
    	for(int i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%mod;
    	inv[n]=inver(fac[n]);
    	for(int i=n;i>=1;--i) inv[i-1]=(ll)inv[i]*i%mod;
    }
    int main() {
    	rd(n),rd(A);
    	init(n);
    	int an=0;
    	for(int t=1;t<=A+1;++t) {
    		for(int j=0,f=1;j<t;++j,f=mod-f) {
    			an=(an+(ll)cal(t-j-1,n-A,max(0,A-t))*binom(t-1,j)%mod*f)%mod;
    		}
    	}
    	printf("%d
    ",an);
    	return 0;
    }
    
  • 相关阅读:
    我最讨厌画图,这辈子我都不想再画图
    bzoj1218[HNOI2003]激光炸弹
    bzoj1196[HNOI2006]公路修建问题
    bzoj1588[HNOI2002]营业额统计
    bzoj2039[2009国家集训队]employ人员雇佣
    bzoj3874[Ahoi2014]宅男计划
    bzoj2282[Sdoi2011]消防
    bzoj1798[Ahoi2009]Seq 维护序列seq
    bzoj4003[JLOI2015]城池攻占
    bzoj2809[Apio2012]dispatching
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13209520.html
Copyright © 2020-2023  润新知