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}{\binom n{A_i}} (\sum_{j\le i} x_j \binom {i-1}{j-1} \binom {n-i}{A_i-j}+\sum_{j \le i} y_j \binom {i-1}{j-1}\binom{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\n",cal(x));
	}
	return 0;
}
posted @ 2020-07-08 20:36  LJZ_C  阅读(121)  评论(0编辑  收藏  举报