正題
題目鏈接: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);
}