P6046-纯粹容器【数学期望,组合数】

正题

题目链接:https://www.luogu.com.cn/problem/P6046
在这里插入图片描述


题目大意

n n n个数,每次选择两个相邻的数删除小的那个,求每个数期望存活轮数。


解题思路

相当于一条链每次缩掉一条边,我们发现其实每个点只需要考虑左右第一个比它大的就好了。定义 P ( x ) P(x) P(x)表示 x x x轮攻击后还没有死亡的概率,有 a n s = ∑ i = 1 n − 1 P ( i ) ans=\sum_{i=1}^{n-1}P(i) ans=i=1n1P(i)

对于每个 P ( i ) P(i) P(i)我们固定到左边第一个比它大的数的路径然后剩下的随便选就可以用组合数来计算方案,而左右两边都减去后要容斥加上两边都被删除的方案数。

时间复杂度 O ( n 2 log ⁡ P ) O(n^2\log P) O(n2logP)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll XJQ=998244353,N=60;
ll n,a[N],fac[N],inv[N],ans;
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%XJQ;
		x=x*x%XJQ;b>>=1;
	}
	return ans;
}
ll C(ll x,ll y)
{
	if(x<0||y<0||x<y)return 0;
	return fac[x]*inv[y]%XJQ*inv[x-y]%XJQ;
}
int main()
{
	scanf("%lld",&n);
	a[0]=a[n+1]=2147483647;
	fac[0]=inv[0]=1;
	for(ll i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		fac[i]=fac[i-1]*i%XJQ;
		inv[i]=inv[i-1]*power(i,XJQ-2)%XJQ;
	}
	for(ll p=1;p<=n;p++){
		ll l=p-1,r=p+1;ans=0;
		while(a[l]<a[p])l--;
		while(a[r]<a[p])r++;
		for(ll i=1;i<n;i++){
			ll tmp=0,d1=p-l,d2=r-p;
			if(l)tmp=(tmp+C(n-1-d1,i-d1))%XJQ;
			if(r!=n+1)tmp=(tmp+C(n-1-d2,i-d2))%XJQ;
			if(r!=n+1&&l)tmp=(tmp-C(n-1-d1-d2,i-d1-d2)+XJQ)%XJQ;
			ans=(ans+1-tmp*power(C(n-1,i),XJQ-2)%XJQ+XJQ)%XJQ;
		}
		printf("%lld ",ans);
	}
}
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页