「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