Problem
Thoughts
我实在不知道为什么我会做这种神题。。
我的想法是这样的。。
利用整数期望公式,则就是每次求P(至少一个区间中的min>=i),如果我们取补集,那就是1-P(每个区间的min都<\i)。而对于某个区间的min<\i则是求P(区间内至少一个数<\i),再取一次补集,即1-P(区间内每个数都>=i)。对于单个区间的问题是比较好处理的,然而注意到区间是允许重叠的,那么区间与区间的期望就不能单独计算,因为会相互影响,因此就难以解决本题。
Solution
前置知识
整数期望公式:
这个和我们常用的
其实是等价的,因为
,这就相当于把原来的P(i)*i拆成i份,加到前面的P之中。
首先还是要反一次,即
。
显然对于一个询问区间包含另一个询问区间的情况下,前者是可以直接舍弃的,因为前者的min<=后者的min。则就只剩下了交叉与分离的询问区间。且其l和r都分别是递增的。
当然由于之前在thoughts里提到的区间重叠的问题,我们转换一下角度,对序列中的元素进行考虑。那么可以预处理出覆盖到点i的询问,显然它应该是一段连续的区间,记为
。而第i个点有
的概率会小于i,对覆盖到它的区间做贡献,使得这些区间满足条件。
不妨设f[i]表示位置i做贡献且1~pre[i]-1的询问全都已经满足条件的概率。枚举上一个做贡献的点,则有方程
最后的答案就是
Code
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=2010,mod=666623333;
struct data{
int l,r;
bool operator < (const data &x)const
{
if(l==x.l) return r>x.r;
return l<x.l;
}
}a[maxn];
struct Stack{
int tp,a[maxn];
Stack(){tp=0;}
void push(int val){a[++tp]=val;}
int top(){return a[tp];}
void pop(){tp--;}
}stk;
int n,x,q,p,pc,ans,pre[maxn],nxt[maxn],inv[maxn],f[maxn];
int power(int x,int y)
{
int res=1;
while(y)
{
if(y&1) res=(ll)res*x%mod;
x=(ll)x*x%mod;y>>=1;
}
return res;
}
void input()
{
int head=1,tail=0;
scanf("%d%d%d",&n,&x,&q);
for(int i=1;i<=q;i++) scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+q+1);
for(int i=1;i<=q;i++)
{
while(a[i].r<=a[stk.top()].r) stk.pop();
stk.push(i);
}
q=stk.tp;
for(int i=1;i<=q;i++) a[i]=a[stk.a[i]];
for(int i=1;i<=n;i++)
{
while(tail<q&&a[tail+1].l<=i) tail++;
while(head<=tail&&a[head].r<i) head++;
pre[i]=head;nxt[i]=tail;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
input();
for(int i=1;i<=x;i++)
{
int j=0,s=1,t=1;
inv[0]=1;f[0]=1;
p=((ll)(i-1+mod)%mod*power(x,mod-2))%mod;
pc=(1-p+mod)%mod;inv[1]=power(pc,mod-2);
for(int k=2;k<=n;k++) inv[k]=(ll)inv[k-1]*inv[1]%mod;
for(int k=1;k<=n;k++)
{
while(j<k&&nxt[j]<pre[k]-1)
s=(s-((ll)f[j]*inv[j]%mod)+mod)%mod,j++;
f[k]=(ll)s*t%mod*p%mod;t=(ll)t*pc%mod;
s=(s+(ll)f[k]*inv[k])%mod;
}
s=0;t=1;
for(int k=n;k>=1&&nxt[k]==q;k--)
s=(s+(ll)f[k]*t%mod)%mod,t=(ll)t*pc%mod;
ans+=(1-s+mod)%mod;
if(ans>=mod) ans-=mod;
}
printf("%d\n",ans);
return 0;
}