题目大意
Alice和Bob在一个大小为 n ( 1 ≤ n ≤ 5000 )的排列P上玩游戏,双方轮流选择数字。
每一轮中,当前玩家需要选择一个比之前双方选择过的元素都大的元素。并且若该玩家之前选择了 P i P_i Pi,当前回合选择了 P j P_j Pj,则必须满足j>i 。若有多种选择,则将等概率的随机选择一个合法的元素。第一回合的玩家会随机选择一个元素,第二回合会随机选择一个比第一回合选择的数字大的元素。没有合法操作时结束游戏。
求游戏结束时,双方的总游戏回合数期望,答案对 9982443533取模。
题解
思路:
用DP算法求出每一步的期望值
设前两个回合选了
P
x
P_x
Px,
P
y
P_y
Py,下一回合选了
P
k
P_k
Pk,
可推出动态方程式为:
当 p x p_x px< p y p_y py时:
d p dp dp[x][y]=1+ 1 c \tfrac{1}{c} c1 ∑ k < y , p k > p y d p k , y \sum\limits_{k<y,pk>py}dp_{k,y} k<y,pk>py∑dpk,y
当 p x p_x px> p y p_y py时:
d p dp dp[x][y]=1+ 1 c \tfrac{1}{c} c1 ∑ k < y , p k > p y d p x , k \sum\limits_{k<y,pk>py}dp_{x,k} k<y,pk>py∑dpx,k
代码
#include<bits/stdc++.h>
using namespace std;
long long mod=998244353;
int a[5010];
long long inv[5010],f[5010][5010],cnt[5010],sum[5010]//sum为前缀;
long long solve(long long x,long long p)
{
long long ret=1;
while(p)
{
if(p%2)
ret=ret*x%mod;
x=x*x%mod;
p>>=1;
}
return ret;
}
int main()
{
int n,i,j;
long long ans,s,c;
inv[0]=1;
for(i=1;i<=5000;i++)
inv[i]=solve(i,mod-2);//预处理
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=n;i>=1;i--)
{
s=c=0;
for(j=n;j>=0;j--)
{
if(i==j) continue;
if(a[i]>a[j])
{
f[i][j]=(s*inv[c]+1)%mod;
sum[j]+=f[i][j];
sum[j]%=mod;
cnt[j]++;
}
else
{
f[i][j]=(sum[j]*inv[cnt[j]]+1)%mod;
s+=f[i][j];
s%=mod;
c++;
}
}
}
ans=0;
for(i=1;i<=n;i++)
ans=(ans+f[i][0])%mod;
ans=ans*inv[n]%mod;
printf("%lld\n",ans);
return 0;
}