关键
计算ai在第i回合死的概率,并且乘上i-1,就是一个贡献值。
但是直接求解在第i回合结束的概率是比较难的,因为战斗顺序是不确定的,所以不能直接求。但是可以求出在第i轮内结束的概率,然后利用容斥,和前面见一下就可以了。
如果这个人要死,只能由左边第一个的比他大的,或者右边第一个的比他大的杀他,(如果这个比他大的被干掉了,留下的还是一个比他大的),所以可以直接排列组合,左边干掉的概率+右边干掉的概率-重合的,也就是两边都打。然后再利用容斥,与前面相减就可以了。
代码
//数学真的就是我的痛
//被左边薄纱的期望+被右边薄纱的期望-被两个人薄纱的期望
//通常使用容斥,我不懂这个的定义为什么是前j轮干掉,而不是在第j轮干掉
//因为我选的规则不好确定,所以是需要容斥的,保证一定是最后干掉
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
const int M=55;
int kpow(int a,int b) {
int ans=1;
while(b) {
if(b&1)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
int inv(int a) {
return kpow(a,mod-2);
}
int C[55][55];
void init() {
for(int i=0;i<=50;i++)
for(int j=0;j<=i;j++) {
if(j==0||j==i)C[i][j]=1;
else C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
int a[M],b[M],ans[M];
signed main() {
init();
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++) {
int L=i,R=i;
for(int j=i-1;j>=1;j--)if(a[j]>a[i]){L=j;break;}
for(int j=i+1;j<=n;j++)if(a[j]>a[i]){R=j;break;}
L=i-L,R=R-i;
if(L==0&&R==0){ans[i]=n-1;continue;}
for(int j=1;j<n;j++) {
b[j]=0;
if(L&&j>=L)b[j]=(b[j]+C[n-1-L][j-L]*inv(C[n-1][j])%mod)%mod;
if(R&&j>=R)b[j]=(b[j]+C[n-1-R][j-R]*inv(C[n-1][j])%mod)%mod;
if(L&&R&&j>=L+R)b[j]=(b[j]-C[n-1-L-R][j-L-R]*inv(C[n-1][j])%mod+mod)%mod;
ans[i]=(ans[i]+(b[j]-b[j-1])*(j-1)%mod+mod)%mod;
}
//cout<<endl;
}
for(int i=1;i<=n;i++)cout<<ans[i]<<' ';
return 0;
}
标签:&&,容器,P6046,int,容斥,纯粹,ans,干掉,mod
From: https://www.cnblogs.com/basicecho/p/17037194.html