[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;
}