正题
题目链接:https://www.luogu.com.cn/problem/P3600
题目大意
个数的序列,每个数是 中的一个,有 个区间 ,求所有区间最小值的最大值的期望。
解题思路
首先如果一个区间包含别的区间,那么这个区间显然不需要考虑,所以去掉后左端点和右端点同时递增,考虑最大值不超过
的方案
,定义
表示放
个点,每个区间至少包括一个点的方案。
有
然后 表示前 个位置, 有点,总共放了 个点的方案,考虑转移, 时要保证 这个区间内没有一个完整的区间,预处理好后有
我们发现 的取值是一段区间,前缀和优化即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2100,XJQ=666623333;
struct node{
ll l,r;
}a[N],b[N];
ll n,x,q,f[N][N],s[N][N],fl[N],fr[N],h[N],g[N],tot,ans;
bool cmp(node x,node y)
{return (x.l==y.l)?(x.r<y.r):(x.l<y.l);}
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;
}
int main()
{
scanf("%lld%lld%lld",&n,&x,&q);
for(ll i=1;i<=q;i++)
scanf("%lld%lld",&b[i].l,&b[i].r);
sort(b+1,b+1+q,cmp);
for(ll i=1;i<=q;i++){
if(i>1&&b[i].l==b[i-1].l)continue;
while(tot&&a[tot].r>=b[i].r)tot--;
a[++tot]=b[i];
}
memset(fl,0x3f,sizeof(fl));
memset(fr,0xcf,sizeof(fr));
for(ll i=1;i<=tot;i++)
for(ll j=a[i].l;j<=a[i].r;j++)
fl[j]=min(fl[j],i),fr[j]=max(fr[j],i);
ll l=0;fl[0]=fr[0]=0;
for(int i=1;i<=n;i++)
if(fr[i]<0)fl[i]=l+1,fr[i]=l;
else l=max(l,fr[i]);
l=0;f[0][0]=s[0][0]=1;
for(ll i=1;i<=n;i++){
while(l<i-1&&fr[l]+1<fl[i])l++;
for(int j=1;j<=i;j++)
if(l)f[i][j]=(s[i-1][j-1]-s[l-1][j-1]+XJQ)%XJQ;
else f[i][j]=s[i-1][j-1];
for(int j=0;j<=i;j++)
s[i][j]=(s[i-1][j]+f[i][j])%XJQ;
}
for(ll i=1;i<=n;i++)
if(fr[i]==tot)
for(ll j=1;j<=n;j++)
(g[j]+=f[i][j])%=XJQ;
for(ll i=1;i<=x;i++)
for(ll j=1;j<=n;j++)
h[i]=(h[i]+g[j]*power(i,j)%XJQ*power(x-i,n-j)%XJQ)%XJQ;
ll z=power(power(x,n),XJQ-2);
for(ll i=n;i>=1;i--)
h[i]=(h[i]-h[i-1]+XJQ)%XJQ;
for(ll i=1;i<=n;i++)
ans=(ans+h[i]*i%XJQ*z%XJQ)%XJQ;
printf("%lld",ans);
}