其他分享
首页 > 其他分享> > 「NOI2019」斗主地

「NOI2019」斗主地

作者:互联网

「NOI2019」斗主地

Part 30

考虑每次洗牌转移一次

设\(f_{i,j}\) 为第一堆牌选出 \(i\) 张,第二堆牌选出 \(j\) 张的概率。设 \(Ans_i\) 为从下往上数第 \(i\) 张的期望分数。

枚举根据定义转移即可。转移式不难写就不写了

Part 40

每个 \(A_i\) 相同,套个矩阵。

Part 100

不难发现 \(Ans_i\) 是一个关于 \(i\) 的多项式,且度为 \(type\)。那么算出前几项的 \(Ans_i\) 即可,后面的都可以直接插值求得。

证明?咕咕咕。贴个别人的好了。https://www.cnblogs.com/Rainbowsjy/p/15743268.html

代码如下:

#include<bits/stdc++.h>
#define ll long long
#define Mod(x) ((x>=MOD)&&(x-=MOD))
using namespace std;
const int MOD = 998244353;
const int MAXN = 5e5+5;
int n,m,type,Q[MAXN],q,A[MAXN];
ll qpw(ll x,ll b)
{
	ll r=1;
	for(;b;b>>=1,x=x*x%MOD) if(b&1) r=r*x%MOD;
	return r;
}
ll tmp[4],f[4][4],Ans[4],inv[10000005];
ll Lag(int x)
{
	ll Ans=0;
	for(int i=1;i<=3;++i)
	{
		ll p=1,q=1;
		for(int j=1;j<=3;++j)
		{
			if(i==j) continue;
			p=p*(x-j+MOD)%MOD;
			q=q*(i-j+MOD)%MOD;
		}
		Ans+=tmp[i]*p%MOD*qpw(q,MOD-2)%MOD;
		Mod(Ans);
	}
	return Ans;
}
int main()
{
	freopen("landlords.in","r",stdin);
	freopen("landlords.out","w",stdout);
	
	scanf("%d %d %d",&n,&m,&type);
	for(int i=1;i<=m;++i) scanf("%d",&A[i]);
	inv[1]=1;for(int i=2;i<=n;++i) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; 
	for(int i=1;i<=3;++i) tmp[i]=type==1?n-i+1:1ll*(n-i+1)*(n-i+1)%MOD;
	for(int cur=1;cur<=m;++cur)
	{
		memset(f,0,sizeof f);
		f[0][0]=1;
		for(int i=0;i<=min(2,A[cur]);++i)
		{
			for(int j=0;j<=min(2,n-A[cur]);++j)
			{
				if(i) f[i][j]+=f[i-1][j]*(A[cur]-i+1)%MOD*inv[n-i-j+1]%MOD;
				Mod(f[i][j]);
				if(j) f[i][j]+=f[i][j-1]*(n-A[cur]-j+1)%MOD*inv[n-i-j+1]%MOD;
				Mod(f[i][j]);
			}
		}
		for(int i=0;i<=2;++i)
		{
			for(int j=0;j<=2;++j)
			{
				if(i+j+1>3) continue;
				ll q=inv[n-i-j];
				if(n-A[cur]-j>0) Ans[i+j+1]+=f[i][j]*Lag(j+1)%MOD*(n-A[cur]-j)%MOD*q%MOD;
				Mod(Ans[i+j+1]);
				if(A[cur]-i>0) Ans[i+j+1]+=f[i][j]*Lag(n-A[cur]+i+1)%MOD*(A[cur]-i)%MOD*q%MOD;
				Mod(Ans[i+j+1]);
			}
		}
		for(int i=1;i<=3;++i) tmp[i]=Ans[i],Ans[i]=0;
	}
	
	scanf("%d",&q);
	for(int i=1;i<=q;++i)
	{
		int x;scanf("%d",&x);
		printf("%lld\n",Lag(n-x+1));	
	}
	return 0;
}

以及 40 分:

#include<bits/stdc++.h>
#define ll long long
#define Mod(x) ((x>=MOD)&&(x-=MOD))
using namespace std;
const int MOD = 998244353;
const int MAXN = 5e5+5;
int n,m,type,Q[MAXN],q,A[MAXN];
ll qpw(ll x,ll b)
{
	ll r=1;
	for(;b;b>>=1,x=x*x%MOD) if(b&1) r=r*x%MOD;
	return r;
}
namespace pt30
{
	ll f[105][105],g[105][105];
	void Solve()
	{
		for(int i=1;i<=n;++i)
			f[0][i]=type==1?(n-i+1):1ll*(n-i+1)*(n-i+1)%MOD;
		for(int cur=1;cur<=m;++cur)
		{
			memset(g,0,sizeof g);
			g[A[cur]][n-A[cur]]=1;
			for(int i=A[cur];i>=0;--i)
				for(int j=n-A[cur];j>=0;--j)
				{
					ll p=qpw(i+1+j,MOD-2);
					if(i+1<=A[cur])g[i][j]+=1ll*g[i+1][j]*(i+1)%MOD*p%MOD;
					if(j+1<=n-A[cur])g[i][j]+=1ll*g[i][j+1]*(j+1)%MOD*p%MOD;
					Mod(g[i][j]);
				}
			for(int i=1;i<=n;++i)
			{
				ll res=0,q=qpw(n-i+1,MOD-2);
				for(int j=1;j<=n-A[cur];++j)
				{
					if(A[cur]+j<i) continue;
					ll p=1ll*(n-A[cur]-j+1)*q%MOD;
					res+=f[cur-1][j]*g[A[cur]-i+j][n-A[cur]-j+1]%MOD*p%MOD;
					Mod(res);
				}
				for(int j=1;j<=A[cur];++j)
				{
					if(n-A[cur]+j<i) continue;
					ll p=1ll*(A[cur]-j+1)*q%MOD;
					res+=f[cur-1][j+n-A[cur]]*g[A[cur]-j+1][n-A[cur]+j-i]%MOD*p%MOD;
					Mod(res);
				}
				f[cur][i]=res;
			}
		}
		for(int i=1;i<=q;++i)
			printf("%lld\n",f[m][n-Q[i]+1]);
	}
}
namespace pt40
{
	struct mat
	{
		ll v[105][105];
		mat(){memset(v,0,sizeof v);}
		mat operator *(const mat&x)const
		{
			mat res;
			for(int k=1;k<=n;++k) for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)
				res.v[i][j]=(res.v[i][j]+v[i][k]*x.v[k][j]%MOD)%MOD;
			return res;
		}
	}t,res;
	ll g[105][105];
	void Solve()
	{
		for(int i=1;i<=n;++i)
			res.v[1][i]=type==1?(n-i+1):1ll*(n-i+1)*(n-i+1)%MOD;
		g[A[1]][n-A[1]]=1;
		for(int i=A[1];i>=0;--i)
			for(int j=n-A[1];j>=0;--j)
			{
				ll p=qpw(i+1+j,MOD-2);
				if(i+1<=A[1])g[i][j]+=1ll*g[i+1][j]*(i+1)%MOD*p%MOD;
				if(j+1<=n-A[1])g[i][j]+=1ll*g[i][j+1]*(j+1)%MOD*p%MOD;
				Mod(g[i][j]);
			}
		for(int i=1;i<=n;++i)
		{
			ll q=qpw(n-i+1,MOD-2);
			for(int j=1;j<=n-A[1];++j)
			{
				if(A[1]+j<i) continue;
				ll p=1ll*(n-A[1]-j+1)*q%MOD;
				t.v[j][i]+=g[A[1]-i+j][n-A[1]-j+1]%MOD*p%MOD;
				Mod(t.v[j][i]);
			}
			for(int j=1;j<=A[1];++j)
			{
				if(n-A[1]+j<i) continue;
				ll p=1ll*(A[1]-j+1)*q%MOD;
				t.v[j+n-A[1]][i]+=g[A[1]-j+1][n-A[1]+j-i]%MOD*p%MOD;
				Mod(t.v[j+n-A[1]][i]);
			}
		}
		ll b=m;
		for(;b;b>>=1,t=t*t) if(b&1) res=res*t;
		for(int i=1;i<=q;++i)
			printf("%lld\n",res.v[1][n-Q[i]+1]%MOD);
	}
}
int main()
{
	freopen("landlords.in","r",stdin);
	freopen("landlords.out","w",stdout);
	
	scanf("%d %d %d",&n,&m,&type);
	for(int i=1;i<=m;++i) scanf("%d",&A[i]);
	scanf("%d",&q);
	for(int i=1;i<=q;++i) scanf("%d",&Q[i]);
	bool Same=1;
	for(int i=2;i<=m;++i) Same&=(A[i]==A[i-1]);
	if(n<=80) pt30::Solve();
	else if(Same) pt40::Solve();
	return 0;
}

标签:cur,int,斗主地,ll,MAXN,Ans,NOI2019,MOD
来源: https://www.cnblogs.com/nightsky05/p/16196152.html