• 【LuoguP3600】随机数生成器-概率DP+双指针


    测试地址:随机数生成器
    做法:本题需要用到概率DP+双指针。
    考虑离散概率情况下的期望公式:
    E[ans]=s=1xsP(ans=s)
    也就相当于:
    E[ans]=s=1xP(anss)
    考虑到P(anss)=1P(anss1),我们只需计算出所有P(anss)即可。
    所有最小值的最大值s,就相当于在每个区间中至少存在一个s的数。那么问题就变成,每个位置有sx的概率被选,求每个区间都至少有一个数被选中的概率。
    但是原本所给的区间比较杂乱,我们需要对这些限制条件做一些简化。显然,如果一个区间严格包含另一个区间,那么这个区间就没有用了,因为被包含那个区间中的数被选中也就意味着该区间的数被选中。所以我们把这样的区间去掉之后,剩下的区间按左端点从小到大排序,右端点也是不降的。
    你有可能在此时想到了直接概率DP的办法,但我这里要介绍另一种办法。显然因为区间的单调性,每个位置被选中所能影响到的区间的区间(没有打错)也是单调的。这样问题就变成,每个区间有P的概率被选,求选中的区间覆盖整个序列的概率。
    那么我们就可以DP了。令f(i)为前i个区间中,选择第i个并且能覆盖从头到第i个区间右端点这一段序列的概率。有状态转移方程:
    f(i)=P(rjli1f(j)(1P)ij1+[li=1](1P)i1)
    实际上就是枚举上一个选择的区间j,显然必须要满足rjli1才可能覆盖整段。而既然要满足j是“上一个”,那么中间的ij1个就不能选,因此要乘上(1P)ij1。而后面要加上的那个东西,是因为当li=1时,是有可能没有“上一个”选择的区间的,所以要多算上这种情况的概率。在这种情况下,最后的答案显然为ri=nf(i)(1P)ti,其中n表示处理后询问的总数,t表示有用的位置总数(不能影响任何区间的位置就是没用的位置,对答案没有影响)。
    这个方程是O(n2)的,不能从方程的角度优化了,因此我们考虑从转移的角度优化。注意到可以把(1P)ij1拆成(1P)j(1P)i1,那么我们就是要求出rjli1f(j)(1P)j。而因为区间的单调性,显然可以用双指针的方法维护这个东西,那么转移就是O(n)的了,而对于1P的一些幂可以O(n)预处理。于是我们就以O(n2)的总时间复杂度完成了这一题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=666623333;
    int n,q;
    ll x;
    struct interval
    {
        int l,r;
    }s[2010];
    bool vis[2010]={0};
    int L[2010],R[2010];
    ll f[2010],antiP[2010][2];
    
    ll power(ll a,ll b)
    {
        ll s=1,ss=a;
        while(b)
        {
            if (b&1) s=s*ss%mod;
            b>>=1;ss=ss*ss%mod;
        }
        return s;
    }
    
    bool cmp(interval a,interval b)
    {
        return a.l<b.l;
    }
    
    int main()
    {
        scanf("%d%lld%d",&n,&x,&q);
        for(int i=1;i<=q;i++)
            scanf("%d%d",&s[i].l,&s[i].r);
        for(int i=1;i<=q;i++)
            for(int j=1;j<=q;j++)
                if (i!=j&&s[i].l<=s[j].l&&s[i].r>=s[j].r)
                    if (s[i].l<s[j].l||s[i].r>s[j].r)
                        vis[i]=1;
        int tot=0;
        for(int i=1;i<=q;i++)
            if (!vis[i])
            {
                s[++tot].l=s[i].l;
                s[tot].r=s[i].r;
            }
        q=tot;
        sort(s+1,s+q+1,cmp);
    
        int l=1,r=0;
        tot=0;
        for(int i=1;i<=n;i++)
        {
            while(r<q&&s[r+1].l<=i) r++;
            while(l<=q&&s[l].r<i) l++;
            if (l<=r) L[++tot]=l,R[tot]=r;
        }
    
        ll ans=0,lastansP=0;
        for(ll p=1;p<=x-1;p++)
        {
            ll ansP=0;
            ll P=p*power(x,mod-2ll)%mod;
            antiP[0][0]=antiP[0][1]=1;
            antiP[1][0]=(1-P+mod)%mod;
            antiP[1][1]=power((1-P+mod)%mod,mod-2);
            for(int i=2;i<=tot;i++)
            {
                antiP[i][0]=(antiP[i-1][0]*antiP[1][0])%mod;
                antiP[i][1]=(antiP[i-1][1]*antiP[1][1])%mod;
            }
    
            l=0;
            ll nowsum=0;
            for(int i=1;i<=tot;i++)
            {
                if (i>1) nowsum=(nowsum+f[i-1]*antiP[i-1][1])%mod;
                while((l==0&&i>1)||R[l]<L[i]-1)
                {
                    l++;
                    if (l>1) nowsum=((nowsum-f[l-1]*antiP[l-1][1])%mod+mod)%mod;
                }
                f[i]=nowsum*antiP[i-1][0]%mod;
                if (L[i]==1) f[i]=(f[i]+antiP[i-1][0])%mod;
                f[i]=f[i]*P%mod;
                if (R[i]==q) ansP=(ansP+f[i]*antiP[tot-i][0])%mod;
            }
    
            ans=((ans+p*(ansP-lastansP))%mod+mod)%mod;
            lastansP=ansP;
        }
        printf("%lld",((ans+x*(1ll-lastansP))%mod+mod)%mod);
    
        return 0;
    }
  • 相关阅读:
    记录一个异常
    ajax4
    ajax3
    ajax2
    ajax
    break与continue的区别
    Dom
    Dom元素的操作
    javascript (2)
    javascript
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793276.html
Copyright © 2020-2023  润新知