• [luogu3600]随机数生成器


    题面在这里

    题意

    给定n个[1-x]的随机整数(a_1,a_2,a_3,...,a_n)和q个询问区间((l_i,r_i)),
    求出(max_{i=1}^{q}({min_{j=l_i}^{r_i}{a_j})})的期望

    对于10%的数据,(n,x,q≤6)
    对于另外20%的数据,(q=1)
    对于50%的数据,(n,x,q≤300)
    对于100%的数据,(1≤n,x,q≤2000),对于每个i,(1≤li≤ri≤n)

    sol

    又是一道期望大火题
    又一次去看题解(我怎么这么菜)

    套路1:区间排序和去重

    考虑两个区间([l1,r1])([l2,r2]),其中(l1geq l2geq r2 geq r1),那么有(min[l1,r1]leq min[l2,r2])
    因此,如果大区间覆盖率小区间,那么大区间对于期望就根本没有贡献(因为小区间的(min)总是会大于大区间),经过一番排序和去重之后可以得到若干个(l)(r)都单调递增的区间,这里的区间个数记为(tot)

    q=1

    接下来我们思考每个询问的结果和最后答案的关系
    一个询问区间中只要有一个数 (leq x),那么这个区间的答案都会(leq x);
    如果每个询问区间的答案都(leq x),那么最后的最大值就会(leq x)
    于是我们可以通过各种组合乱搞来满足上面的需求,
    得到单个询问区间结果(leq x)的概率(P(ansleq x))
    当q=1的时候(sum_{i=1}^{i=x}{(P(ansleq i)-P(ansleq i-1))*i})就是答案啦
    并且根据上面的式子我们可以继续往下推出

    一个重要的公式

    对于一个随机正整数变量(kgeq 0),其期望

    [E(k)=sum_{i=1}^{inf}{P(kgeq i)} ]

    update 3.27:其实就是一个差分嘛
    考虑暴力求出(P(k geq i))
    按照上面的思路,一个更好的做法是求出(P(kleq i-1))那么其实

    [E(k)=sum_{i=1}^{x}{P(kgeq i)}=sum_{i=1}^{x}{(P(kleq i)-P(kleq i-1))*i}=x-sum_{i=0}^{x-1}{P(kleq i)} ]

    (因为(P(kleq x)==1))
    于是对于每一个(P(kleq x))我们暴力计算

    套路2:考虑单个元素贡献(n,x,q≤300)

    需要转换一下思路:考虑每一个数(a_i)能满足哪些区间
    由于我们之前已经对区间进行了去重和排序,
    那么我们可以知道,每个元素所在的询问集合一定是一个连续的区间
    意即只要这一个元素(leq i),那么这个元素所在的询问集合的取值都会(leq i);
    而我们需要用某些元素满足所有的询问
    因此这个问题转换成了一个区间覆盖问题:
    我们有(n)个区间((n)个元素各对应一个询问集合),每个询问区间有(p=P(kleq i)=frac{i}{x})的概率被取到,求整段([1-q])被覆盖的概率

    于是我们可以设置状态(f[i])表示强制选择第(i)个区间,并且选择区间集合包含了前(i)个区间的右端点的概率,则

    [f[i]=(sum_{j=1,r[j]>=l[i]-1}^{i-1}{f[j] imes(1-p)^{i-j-1}} imes p)+[l[i]==1](1-p)^{i-1} imes p ]

    最后$$Ans=sum_{i=1,r[i]==n}{n}{(f[i] imes(1-p){n-i})}$$
    然而这个转移是(O(n^2))的有木有!!!
    其实有另一种更简单的50分做法,由于跟正解关系不大故不做赘述

    最后的DP优化:单调指针/前缀和(1≤n,x,q≤2000)

    可以看出我们每次需要O(n)计算的一大段(sum_{j,r[j]>=l[i]-1}^{i-1}{f[j] imes(1-p)^{i-j-1}})其实是一段连续并且左端点和右端点均单调不降的
    因此使用单调指针记录这个值即可,一次DP的复杂度降为(O(n))
    update 3.27:直接记录一个前缀和就可以啦!!!
    总复杂度(O(nx))

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    const int mod=666623333;
    const int N=2010;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    il ll read(){
        RG ll data=0,w=1;RG char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')w=-1,ch=getchar();
        while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
        return data*w;
    }
    
    il ll poww(ll a,ll b){
        a=(a%mod+mod)%mod;RG ll ret=1;
        for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod;
        return ret;
    }
    il ll fac(ll x){if(!x)return 1;return fac(x-1)*x%mod;}
    
    int tot,cnt;
    struct line{int l,r;}T[N],Q[N],L[N];
    bool cmp(line a,line b){return a.l==b.l ? a.r<b.r : a.l<b.l;}
    int n,x,q,ans;
    
    il void init(){
        n=read();x=read();q=read();
        for(RG int i=1;i<=q;i++){T[i].l=read();T[i].r=read();}
        sort(T+1,T+q+1,cmp);
        for(RG int i=1;i<=q;i++){
            while(Q[tot].r>=T[i].r&&tot)tot--;
            if(Q[tot].l<T[i].l&&Q[tot].r<T[i].r)Q[++tot]=T[i];
        }
        for(RG int i=Q[1].l,pl=1,pr=0;i<=n;i++){
            while(Q[pl].r<i&&pl<=tot)pl++;
            while(Q[pr+1].l<=i&&pr!=tot)pr++;
            L[++cnt]=(line){pl,pr};
        }
    }
    
    int f[N];
    il int calc(int a){
        RG int p=1ll*(a-1)*poww(x,mod-2)%mod,sum=0;
        RG int fp=(1-p+mod)%mod,revfp=poww(fp,mod-2);
        memset(f,0,sizeof(f));
        
        for(RG int i=1,l=1,r=0,S=0,k=0;i<=cnt;i++){
            if(L[i].l==1)f[i]=poww(fp,i-1);
            
            while(L[r+1].r>=L[i].l-1&&r+1<i)
                r++,S=(S+1ll*f[r]*poww(fp,cnt-r-1)%mod)%mod;
            while(L[l].r<L[i].l-1&&l<r)
                S=(S-1ll*f[l]*poww(fp,cnt-l-1)%mod+mod)%mod,l++;
            f[i]=1ll*(f[i]+1ll*S*poww(revfp,cnt-i)%mod)%mod*p%mod;
        }
        
        for(RG int i=1;i<=cnt;i++)
            if(L[i].r==tot)
                sum=(sum+1ll*f[i]*poww(1-p+mod,cnt-i)%mod)%mod;
        
        return sum;
    }
    
    il void solve(){	
        for(RG int i=1;i<=x;i++)
            ans=(ans+(1-calc(i)+mod))%mod;
        printf("%d
    ",ans);
    }
    
    int main()
    {
        init();
        solve();
        return 0;
    }
    
  • 相关阅读:
    python16_day03【集合、编码、函数、递归、内置函数】
    python16_day02【列表、字典】
    django 自定义用户表替换系统默认表
    用国内镜像源pip加速安装模块
    python虚拟环境的搭建命令mkvirtualenv
    测试分类
    bug理论
    测试用例的优先级
    测试流程
    测试理论
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8422946.html
Copyright © 2020-2023  润新知