Luogu P3600 随机数生成器(期望和概率dp)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88383768

题目
不得不说,一 m i n min m a x max 加一个期望把我搞晕了。
其实这个题它和你说答案为整数其实就可以想到枚举答案,从而把期望问题化为概率问题
E ( x ) = i = 1 X i P ( x = i ) = i = 1 X i ( P ( x > = i ) P ( x > = i + 1 ) ) E(x) = \sum_{i=1}^XiP(x=i)=\sum_{i=1}^Xi\left(P(x>=i)-P(x>=i+1)\right)
如果还要再优秀一点:
E ( x ) = i = 1 X P ( x > = i ) E(x)=\sum_{i=1}^XP(x>=i)
现在发现 P ( x > = i ) P(x>=i) 就可以算了。但是这个x是所有最小值的最大值,它大于等于某个数等价于所有最小值中有存在大于等于这个数的最小值,如果我们用 P ( x > = i ) = 1 P ( x < i ) P(x>=i) = 1 - P(x<i) ,那么就是所有最小值都小于这个数,明显后者的dp式子好写一点。。。。。。
d p [ i ] dp[i] 为位置 i i 小于这个数并且位置i前不存在:内部没有小于这个数的线段,
p p 为一个随机数小于这个数的概率。
d p [ i ] = p j = 0 i d p [ j ] ( 1 p ) i j 1 dp[i] = p*\sum_{j=0}^i dp[j]*(1-p)^{i-j-1}
完了?
是的。

#include<bits/stdc++.h>
#define maxn 2005
#define mod 666623333ll
#define LL long long
using namespace std;

int n,x,q,mx[maxn];
LL f[maxn],P[2][maxn],g[maxn];

template<class T1,class T2>T1 Pow(T1 base,T2 k)
{
	T1 ret = 1;
	for(;k;k>>=1,base=1ll*base*base%mod)
		if(k&1)
			ret = 1ll * ret * base % mod;
	return ret;
}

int main()
{
	scanf("%d%d%d",&n,&x,&q);
	for(int i=1;i<=q;i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		mx[r+1] = max(mx[r+1],l);
	}
	for(int i=1;i<=n+1;i++) mx[i] = max(mx[i] , mx[i-1]);
	LL invx = Pow(x,mod-2) ,ans = 0;
	for(int i=0;i<x;i++)
	{
		LL p = 1ll * i * invx % mod , inp = Pow(1-p,mod-2);
		P[0][0] = P[1][0] = 1;
		for(int j=1;j<=n;j++) 
			P[0][j] = P[0][j-1] * (1-p) % mod,
			P[1][j] = P[1][j-1] * inp % mod;
		
		f[0] = 0 , g[0] = 1;
		for(int j=1;j<=n;j++)
		{
			f[j] = p * (g[j-1] - (mx[j] ? g[mx[j]-1] : 0)) % mod * P[0][j-1] % mod;
			g[j] = (f[j] * P[1][j] + g[j-1]) % mod;
		}
		
		LL sum = 0;
		for(int j=mx[n+1];j<=n;j++) sum = (sum + 1ll * f[j] * P[0][n-j]) % mod;
		ans = (ans + 1 - sum) % mod;
	}
	printf("%lld\n",(ans+mod)%mod);	
}

upd:出题人说把x开到10^7也是可以做的。。。
我猜测:
答案是一个关于p的n次多项式,可以 O ( n 2 ) O(n^2)

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/88383768