• P3600 随机数生成器


    传送门

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

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

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

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

    然而因为这里要计算的是最小值,如果是大于等于很不方便,于是我们考虑转化为(P(ansgeq 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
    ",ans);return 0;
    }
    
  • 相关阅读:
    浅谈java中异常处理
    Android四大组件之BroadcastReceiver
    android基本组件 Button
    Android基本组件TextView和EditView
    Unicode,GBK和UTF8
    记一次生产上的紧急修复之后解疑过程
    使用第三方jar时出现的问题
    码农歌单
    创建servlet程序知识点详解---servlet-day12
    创建servlet程序知识点详解---servlet-day07
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9965946.html
Copyright © 2020-2023  润新知