洛谷3600 随机数生成器

Problem

洛谷

Thoughts

我实在不知道为什么我会做这种神题。。

我的想法是这样的。。
利用整数期望公式,则就是每次求P(至少一个区间中的min>=i),如果我们取补集,那就是1-P(每个区间的min都<\i)。而对于某个区间的min<\i则是求P(区间内至少一个数<\i),再取一次补集,即1-P(区间内每个数都>=i)。对于单个区间的问题是比较好处理的,然而注意到区间是允许重叠的,那么区间与区间的期望就不能单独计算,因为会相互影响,因此就难以解决本题。

Solution

前置知识
整数期望公式: E ( x ) = i P ( x >= i )
这个和我们常用的 E ( x ) = i P ( i ) i 其实是等价的,因为 P ( x >= i ) = j = i P ( j ) ,这就相当于把原来的P(i)*i拆成i份,加到前面的P之中。

首先还是要反一次,即 E ( a n s ) = i x 1 P ( a n s < i )
显然对于一个询问区间包含另一个询问区间的情况下,前者是可以直接舍弃的,因为前者的min<=后者的min。则就只剩下了交叉与分离的询问区间。且其l和r都分别是递增的。
当然由于之前在thoughts里提到的区间重叠的问题,我们转换一下角度,对序列中的元素进行考虑。那么可以预处理出覆盖到点i的询问,显然它应该是一段连续的区间,记为 [ p r e [ i ] , n x t [ i ] ] 。而第i个点有 i 1 x 的概率会小于i,对覆盖到它的区间做贡献,使得这些区间满足条件。
不妨设f[i]表示位置i做贡献且1~pre[i]-1的询问全都已经满足条件的概率。枚举上一个做贡献的点,则有方程

f [ i ] = p n x t [ j ] < p r e [ i ] 1 f [ j ] ( 1 p ) i j 1 + [ p r e [ i ] == 1 ] ( 1 p ) i 1

最后的答案就是 n x t [ i ] == q f [ i ] ( 1 p ) n i

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;
}

猜你喜欢

转载自blog.csdn.net/as_a_kid/article/details/80382372