[luogu P3600] 随机数生成器

\(\text{Problem}:\)随机数生成器

\(\text{Solution}:\)

设答案为 \(W\),则要求的是 \(E(W)=\sum\limits_{i=1}^{x}P(W\geq i)\)

这题要求的是所有最小值的最大值,可以改变一下,设所有区间都满足 \(\min_{l,r}\leq k\) 的概率为 \(P(k)\),那么 \(E(W)=\sum\limits_{i=1}^{x}i\times (P(i)-P(i-1))\)。现在考虑如何求 \(P(k)\)

首先,如果区间 \([l1,r1]\) 包含区间 \([l2,r2]\),那么 \([l1,r1]\) 这个区间是无用的(因为 \([l2,r2]\) 满足条件,\([l1,r1]\) 也一定满足条件)。现在将剩下的区间以左端点为关键字排序,不难发现其右端点也是有序的。对于每个点 \(i\in[1,n]\) 单独考虑,它能产生贡献的概率为 \(\cfrac{k}{x}\),并且所有覆盖 \(i\) 的区间都满足了条件。那么问题转化为:每个点有 \(\cfrac{k}{x}\) 的概率覆盖连续的一些区间,求所有区间都被覆盖的概率。

\(L_{i}\) 表示 \(i\) 能覆盖到的最左边的区间,\(R_{i}\) 表示 \(i\) 能覆盖到的最右边的区间。再转化一步,问题为:在 \([1,n]\) 中选择若干个点,每个点 \(p\) 的权值有 \(x\) 种选择,其中有 \(k\) 种选择使得这个点覆盖了 \([l_{p},r_{p}]\) 的区间,求给 \(n\) 个点分配权值,使得它们覆盖了所有区间的方案数。它显然为 \(P(k)\times x^{n}=\sum\limits_{i}f_{i}\times k^{i}\times (x-k)^{n-i}\)。特殊的,令 \(0^{0}=1\)\(f_{i}\) 表示选择 \(i\) 个点(不考虑权值),使得所有区间被覆盖的方案数。则要求的就是 \(f_{i}\)

\(g_{i,j}\) 表示必选第 \(i\) 个点,已经选了 \(j\) 个点的方案数。考虑从 \(j\) 转移到 \(i\),要满足 \(r_{j}\geq l_{i}-1\)\(g_{i,x}=\sum\limits_{j}g_{j,x-1}\)。那么 \(f_{i}=\sum\limits_{r_{j}=m}g_{j,i}\)。而 \(j\) 的转移是一段区间,左端点是单调的,可以前缀和转移,那么求出 \(g\) 的时间复杂度为 \(O(n^{2})\)。总时间复杂度 \(O(n^2\log n)\),预处理一下 \(i^{j}\)\(i,j\leq 2000\))就 \(O(n^2)\) 了。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=2010, Mod=666623333;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,X,Q,m,book[N],G[N][N],L[N],R[N],g[N][N],P[N],f[N],qz[N];
struct Node { int l,r; }e[N];
inline bool cp(Node x,Node y) { return x.l<y.l; }
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
signed main()
{
	n=read(), X=read(), Q=read();
	for(ri int i=1;i<=Q;i++) e[i].l=read(), e[i].r=read();
	for(ri int i=1;i<=Q;i++)
	{
		if(G[e[i].l][e[i].r]) continue;
		G[e[i].l][e[i].r]=1;
		e[++m]=e[i];
	}
	Q=0;
	for(ri int i=1;i<=m;i++)
	{
		for(ri int j=1;j<=m;j++)
		{
			if(i==j) continue;
			if(e[j].l>=e[i].l&&e[j].r<=e[i].r) { book[i]=1; continue; }
		}
	}
	for(ri int i=1;i<=m;i++) if(book[i]!=1) e[++Q]=e[i];
	m=Q;
	sort(e+1,e+1+m,cp);
	for(ri int i=1,l=1,r=1;i<=n;i++)
	{
		while(l<=m && e[l].r<i) l++;
		while(r<=m && e[r].l<=i) r++;
		L[i]=l, R[i]=r-1;
	}
	g[0][0]=qz[0]=1;
	for(ri int i=1;i<=n;i++) qz[i]=qz[i-1];
	for(ri int i=1;i<=n;i++)
	{
		int now=0;
		for(ri int j=1;j<=n;j++)
		{
			while(now<j && R[now]<L[j]-1) now++;
			if(now>=j) continue;
			g[j][i]=qz[j-1];
			if(now) g[j][i]-=qz[now-1];
			if(g[j][i]<0) g[j][i]+=Mod;
		}
		qz[0]=0;
		for(ri int j=1;j<=n;j++)
		{
			qz[j]=(qz[j-1]+g[j][i])%Mod;
			if(R[j]==m) f[i]=(f[i]+g[j][i])%Mod;
		}
	}
	for(ri int i=1,inv=ksc(ksc(X,n),Mod-2);i<=X;i++)
	{
		for(ri int j=1;j<=n;j++)
		{
			int w=1ll*f[j]*ksc(i,j)%Mod;
			w=1ll*w*ksc(X-i,n-j)%Mod;
			P[i]=(P[i]+w)%Mod;
		}
		P[i]=1ll*P[i]*inv%Mod;
	}
	int ans=0;
	for(ri int i=1;i<=X;i++) (ans+=1ll*i*(P[i]-P[i-1]+Mod)%Mod)%=Mod;
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-04-15 21:28  zkdxl  阅读(61)  评论(0编辑  收藏  举报