zoukankan      html  css  js  c++  java
  • 随机数生成器

    随机数生成器

    有一长度为n的序列,序列每个位置等概率出现([1,x])的整数,有q个询问,询问区间([l,r])的最小值,现在要求q个询问的结果的最大值的期望(mod 666623333),1≤n,x,q≤2000。

    显然问题的结果必然为分数形式,而总方案确定(x^n),所以每种情况下概率确定,我们只要想办法统计方案数即可,接下来变为组合计数问题。

    于是设(A[i])表示最大值为i的方案数,显然不好求,因为一旦你限定一些结果为i,必然剩下的询问结果都必须小于i,而接下来划分问题就会发生重复,于是不得不用容斥原理,而显然数据范围不接受,而且很麻烦。

    考虑更换状态,利用拆分,设(A[i])表示最大值小于等于i的方案数,不难得知,此时要让询问结果的最大值小于等于i,即所有区间的最小值都要小于等于i,而对于这个问题,我们只要限定覆盖区间内的一些位置必然小于i即可,于是设(B[i])表示用i个点覆盖所有区间的方案数,于是

    [A[i]=sum_{j=1}^nB[j]j^i(n-j)^{x-i} ]

    现在问题在于求(B[i]),于是设(C[i][j])表示填到第i个位置,有j个已经填了,覆盖所有区间的方案数,并设(fl[i],fr[i])分别表示覆盖第i个位置最左边的区间,最右边的区间,特别地当第i个位置不被任何区间覆盖,分别表示最靠近的左边的区间和最右边的区间。

    于是不难得知

    [C[i][j]=sum_{fl[k]+1geq fr[i]}C[k][j-1] ]

    而有注意到用于转移的状态为连续的,考虑前缀和优化,故时间复杂度为(O(n^2))

    于是求出要求的所有式子,答案就应为

    [ans=frac{sum_{i=1}^x(A[i]-A[i-1]) imes i}{x^n} ]

    以此求出逆元进行计算即可。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define yyb 666623333
    using namespace std;
    struct interval{
        int l,r;
        il bool operator<(interval&x){
            return (l==x.l)?(r>x.r):(l<x.l);
        }
    }I[2001],s[2001];int top;
    ll g[2001][2001],opt[2001][2001],ans,
        h[2001],p[2001];int fl[2001],fr[2001];
    il void read(int&);
    il ll frac(ll,ll),pow(ll,ll);
    int main(){
        int n,x,q,i,j,k;
        read(n),read(x),read(q);
        for(i=1;i<=q;++i)read(I[i].l),read(I[i].r);
        sort(I+1,I+q+1);
        for(i=1;i<=q;++i){
            while(top&&s[top].r>=I[i].r)--top;
            s[++top]=I[i];
        }q=top;
        for(i=1;i<=n;++i){
            for(j=1;j<=q;++j)if(s[j].r>=i)break;fl[i]=j;
            for(j=q;j>=1;--j)if(s[j].l<=i)break;fr[i]=j;
        }g[0][0]=opt[0][0]=1;
        for(i=1;i<=n;++i){
            k=fl[i]-1;
            for(j=1;j<=n;++j)
                g[i][j]=(opt[i-1][j-1]-(k?opt[s[k].l-1][j-1]:0))%yyb;
            for(j=0;j<=n;++j)opt[i][j]=(opt[i-1][j]+g[i][j])%yyb;
        }
        for(i=s[q].l;i<=n;++i)
            for(j=1;j<=n;++j)(h[j]+=g[i][j])%=yyb;
        for(i=1;i<=x;++i)
            for(j=1;j<=n;++j)
                (p[i]+=h[j]*pow(i,j)%yyb*pow(x-i,n-j))%=yyb;
        for(i=1;i<=x;++i)(ans+=(p[i]-p[i-1])*i)%=yyb;
        (ans+=yyb)%=yyb,printf("%lld
    ",frac(ans,pow(x,n)));
        return 0;
    }
    il ll frac(ll a,ll b){
        return a*pow(b,yyb-2)%yyb;
    }
    il ll pow(ll x,ll y){
        ll ans(1);while(y){
            if(y&1)(ans*=x)%=yyb;
            (x*=x)%=yyb,y>>=1;
        }return ans;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    集合已修改 ;可能无法执行枚举操作 Dictionary
    net 操作XML小结
    SQL SERVER 2000写存储过程出现列名无效的解决方法
    .net如何获得前一页面的地址
    SQL字符串叠加问题
    c# 保留2位小数
    如何取字符字段的第几个字符,如取name的左边从2位起的2个字符?
    SQL语句复制表的方法
    给页面加上Loading效果最简单实用的办法
    为XMl文档添加子节点,依据淘宝
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10852657.html
Copyright © 2011-2022 走看看