P3600 随机数生成器

传送门

全世界的题解都看不懂.jpg

题解写到一半莫名刷新结果全都白写了.jpg

首先要知道全概率公式\(E(x)=\sum_{i=0}^\infty P(x\geq i)\),证明如下

于是对于每一个\(i\),我们只要计算出\(P(ans\geq i)\)即可

然而因为这里要计算的是最小值,如果是大于等于很不方便,于是我们考虑转化为\(P(ans\geq i)=1-P(ans<i)\),也就是意味着每一个区间中都至少有一个数小于等于\(i-1\)

有一个性质,如果区间\(a=[l1,r1]\)完全包含了区间\(b=[l2,r2]\),那么\(a\)是没有用的,因为\(a\)的最小值肯定小于等于\(b\)的最小值,对答案不可能有贡献。于是我们可以先把所有包含了其它区间的区间先去掉,再按左端点排一个序,那么右端点肯定也是递增的

考虑一个数,如果它小于等于\(i-1\)那么它会对一些区间产生贡献,且这些区间的编号肯定是连续的。我们把点和区间翻转,考虑用点去覆盖区间,那么现在的问题就变成了每个点能覆盖一些区间,且覆盖的概率为\(p=\frac{i-1}{x}\),问所有区间都被覆盖的概率

\(l[i]\)\(i\)能覆盖到的最左边的区间,\(r[i]\)为最右边的区间,\(f[i]\)为必选第\(i\)个点,且\(r[i]\)及其之前的区间都被覆盖的概率,那么有\[f[i]=p*(\sum_{r[j]\geq l[i]-1} f[j]*(1-p)^{i-j-1}+[l[i]=1]*(1-p)^{i-1})\]

就是说我们枚举上一个选的点\(j\),那么必须有\(r[j]\geq l[i]-1\)才能保证\(r[i]\)及其之前的区间都被覆盖,又因为\(j\)是上一个被选的,所以\([j+1,i-1]\)都没有被覆盖。

那么最后的答案就是\(\sum_{r[i]=m} f[i]*(1-p)^{n-i}\),就是枚举最后一个被选的点,然后因为它是最后一个,所以\([i+1,n]\)都没被覆盖

这个东西用双指针的话,可以优化到\(O(n)\)

//minamoto
#include<bits/stdc++.h>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=2005,mod=666623333;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
int ksm(int a,int b){
    int res=1;
    for(;b;b>>=1,a=mul(a,a))if(b&1)res=mul(res,a);
    return res;
}
struct node{
    int l,r;
    inline bool operator <(const node &b)const
    {return l==b.l?r>b.r:l<b.l;}
}a[N];
int n,k,m,st[N],top,L[N],R[N],f[N],ans,invp[N];
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),k=read(),m=read();for(int i=1;i<=m;++i)a[i].l=read(),a[i].r=read();
    sort(a+1,a+1+m);
    for(int i=1;i<=m;++i){
        while(top&&a[i].r<=a[st[top]].r)--top;
        st[++top]=i;
    }
    m=top;for(int i=1;i<=m;++i)a[i]=a[st[i]];
    int h=1,t=0;
    for(int i=1;i<=n;++i){
        while(t<m&&a[t+1].l<=i)++t;
        while(h<=t&&a[h].r<i)++h;
        L[i]=h,R[i]=t;
    }
    for(int x=1;x<=k;++x){
        int sum,p,np,fp,leip,tot;
        sum=1,p=mul(dec(x,1),ksm(k,mod-2));
        np=dec(1,p),fp=ksm(np,mod-2);
        invp[0]=1,f[0]=1,leip=1;
        for(int i=1;i<=n;++i)invp[i]=mul(invp[i-1],fp);
        for(int i=1,j=0;i<=n;++i){
            while(j<i&&R[j]<L[i]-1)sum=dec(sum,mul(f[j],invp[j])),++j;
            f[i]=mul(sum,mul(leip,p)),leip=mul(leip,np);
            sum=add(sum,mul(f[i],invp[i]));
        }
        tot=0,leip=1;
        for(int i=n;i&&R[i]==m;--i,leip=mul(leip,np))tot=add(tot,mul(f[i],leip));
        ans=add(ans,dec(1,tot));
    }
    printf("%d\n",ans);return 0;
}

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/9965946.html