zoukankan      html  css  js  c++  java
  • loj 3160 [NOI2019] 斗主地

    loj 3160 [NOI2019] 斗主地

    https://loj.ac/problem/3160

    UZJ0TU.png

    UZJsfJ.png

    UZJWm6.png

    Tutorial

    https://hyscere.github.io/2019/12/19/%E3%80%8CNOI2019%E3%80%8D%E6%96%97%E4%B8%BB%E5%9C%B0/

    很容易得到一个 (O(mn^2)) 的暴力,第(i)次洗牌时,设两堆牌期望分别为(x_1,x_2,cdots),(y_1,y_2,cdots),洗牌后的期望(z)

    [z_i= dfrac {1}{inom n{A_i}} (sum_{jle i} x_j inom {i-1}{j-1} inom {n-i}{A_i-j}+sum_{j le i} y_j inom {i-1}{j-1}inom{n-i}{(n-A_i)-j}) ]

    打表后发现,如果type=1,那么无论洗牌多少次,期望总是一次函数,type=2时总是二次函数

    所以我们只需要维护(x_1,x_2,x_3),每次洗牌时,用拉格朗日插值算出(y_1,y_2,y_3),然后暴力转移即可.

    对于询问也用拉格朗日插值计算答案.

    复杂度 (O(m))

    Code

    #include <cstdio>
    #include <iostream>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define inver(a) power(a,mod-2)
    using namespace std;
    inline char gc() {
    	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=998244353;
    int n,m,type,a[5];
    int s1[5],s2[5],s3[5],C[5][5],fac[5],inv[5];
    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 cal(int x) {
    	static int pre[5],suf[5];
    	pre[0]=1;
    	for(int i=1;i<=3;++i) pre[i]=(ll)pre[i-1]*sub(x-i)%mod;
    	suf[4]=1;
    	for(int i=3;i>=1;--i) suf[i]=(ll)suf[i+1]*sub(x-i)%mod;
    	int re=0;
    	for(int i=1;i<=3;++i) {
    		int c=(ll)pre[i-1]*suf[i+1]%mod*inv[i-1]%mod*inv[3-i]%mod*((3-i)&1?mod-1:1)%mod;
    		re=(re+(ll)c*a[i])%mod;
    	}
    	return re;
    }
    void init(int *s,int n) {
    	s[0]=1;
    	for(int i=1;i<=3;++i) s[i]=(ll)s[i-1]*(n-i+1)%mod; 
    }
    void init() {
    	fac[0]=1;
    	for(int i=1;i<=3;++i) fac[i]=(ll)fac[i-1]*i%mod;
    	inv[3]=inver(fac[3]);
    	for(int i=3;i>=1;--i) inv[i-1]=(ll)inv[i]*i%mod;
    	for(int i=0;i<=3;++i) {
    		C[i][0]=C[i][i]=1;
    		for(int j=1;j<i;++j) C[i][j]=add(C[i-1][j-1]+C[i-1][j]);
    	}
    	init(s1,n);
    	for(int i=1;i<=3;++i) s1[i]=inver(s1[i]);
    }
    int main() {
    	freopen("landlords.in","r",stdin);
    	freopen("landlords.out","w",stdout);
    	rd(n),rd(m),rd(type);
    	init();
    	for(int i=1;i<=3;++i) a[i]=type==1?i:i*i;
    	for(int i=1;i<=m;++i) {
    		static int A[5],B[5];
    		int c; rd(c);
    		for(int i=1;i<=3;++i) A[i]=i<=c?a[i]:0;
    		for(int i=1;i<=3;++i) B[i]=c+i<=n?cal(c+i):0;
    		init(s2,c),init(s3,n-c);
    		for(int i=1;i<=3;++i) {
    			a[i]=0;
    			for(int j=1;j<=3;++j) {
    				a[i]=(a[i]+(ll)A[j]*C[i-1][j-1]%mod*s1[i]%mod*s2[j]%mod*s3[i-j])%mod;
    				a[i]=(a[i]+(ll)B[j]*C[i-1][j-1]%mod*s1[i]%mod*s3[j]%mod*s2[i-j])%mod;
    			}
    		}
    	}
    	int Q; rd(Q);
    	for(int i=1;i<=Q;++i) {
    		int x; rd(x);
    		printf("%d
    ",cal(x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    练习2
    练习1
    如何生成添加前缀的顺序DIV
    mysql5.7 版本中 timestamp 不能为零日期 以及sql_mode合理设置
    MIME类型大全
    Intel Xeon E5-2620 v4参数
    webgl开发中添加IIS的mime类型
    jquery.validate动态更改校验规则
    mvc4
    asp.net防SQL/JS注入攻击:过滤标记
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13269101.html
Copyright © 2011-2022 走看看