zoukankan      html  css  js  c++  java
  • 「PMOI-1」发怒

    Solution

    容易发现使得一个区间的数都相同的最小操作次数即为区间极差。那么抽一次区间且发怒的概率就为极差大于 (K) 的区间个数除以总区间个数。容易想到用两个单调队列维护这一过程。将这个概率记为 (P_0)

    那么抽 (t) 个区间发怒次数的 (p) 次方的期望就为

    [Ans(t)=sum_{omega in Omega} X(omega)^p Pr(omega)=sum_{i=0}^t inom{t}{i} P_0^i (1-P_0)^{t-i} i^p ]

    把二项式系数拆了,并分类,得

    [Ans(t)=t!sum_{i=0}^t frac{P_0^i i^p}{i!} imes frac{(1-P_0)^{t-i}}{(t-i)!} ]

    NTT 优化即可快速求出所有 (Ans(t))

    Tips

    写代码的时候不要把 (P_0)(p) 搞混了,最好用不同的变量名。

    #include<stdio.h>
    #define Mod 998244353
    #define ll long long
    #define N (1<<22)+3
    #define rint register int
    
    const int G=3;
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    ll qpow(ll x,ll y){
        ll ret=1,cnt=0;
        while(y>=(1LL<<cnt)){
            if(y&(1LL<<cnt)) ret=(ret*x)%Mod;
            x=(x*x)%Mod,cnt++;
        }
        return ret;
    }
    
    const int Gi=qpow(G,Mod-2);
    
    int n,k,p,op,rk[N];
    int now=1,h1=1,h2=1,t1=0,t2=0,Q1[N],Q2[N];
    
    ll fac[N],inv[N],a[N],b[N];
    
    ll C(int n,int m){return n<m? 0:fac[n]*inv[m]%Mod*inv[n-m]%Mod;}
    /* Q1 max Q2 min*/
    
    inline void swap(ll &x,ll &y){x^=y,y^=x,x^=y;}
    inline void NTT(ll *F){
        for(rint i=0;i<n;i++)
            if(i<rk[i]) swap(F[i],F[rk[i]]);
        for(rint p=2;p<=n;p<<=1){
            int len=p>>1;
            ll w=qpow(op? G:Gi,(Mod-1)/p);
            for(rint k=0;k<n;k+=p){
                ll now=1;
                for(rint l=k;l<k+len;l++){
                    ll t=now*F[l+len]%Mod;
                    F[l+len]=(F[l]-t+Mod)%Mod;
                    F[l]=(F[l]+t)%Mod;
                    now=now*w%Mod;
                }
            }
        }
    }
    
    int main(){
        fac[0]=1;
        for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%Mod;
        inv[N-1]=qpow(fac[N-1],Mod-2);
        for(int i=N-2;~i;i--) inv[i]=inv[i+1]*(i+1)%Mod;
        n=read(),k=read(),p=read();
        ll ret=0;
        for(int i=1;i<=n;i++){
            a[i]=read();
            while(h1<=t1&&a[Q1[t1]]<=a[i]) t1--;
            while(h2<=t2&&a[Q2[t2]]>=a[i]) t2--;
            Q1[++t1]=i,Q2[++t2]=i;
            while(now<i-1){
                int x1=(now==Q1[h1]? a[Q1[h1+1]]:a[Q1[h1]]);
                int x2=(now==Q2[h2]? a[Q2[h2+1]]:a[Q2[h2]]);
                if(x1-x2<=k) break;
                if(now==Q1[h1]) h1++;
                if(now==Q2[h2]) h2++;
                now++;
            }
            if(a[Q1[h1]]-a[Q2[h2]]>k) ret+=1ll*now;
        }
        ret=ret*2ll%Mod*qpow(1ll*n*(n+1)%Mod,Mod-2)%Mod;
        ll ans=0;
        for(int i=0;i<=n;i++)
            a[i]=qpow(ret,i)*qpow(i,p)%Mod*inv[i]%Mod,
            b[i]=qpow(1-ret+Mod,i)*inv[i]%Mod;
        int n_=n;
        for(n=1;n<=(n_<<1);n<<=1);
        for(rint i=0;i<n;i++)
            rk[i]=(rk[i>>1]>>1)|((i&1)? n>>1:0);
        op=1,NTT(a),NTT(b);
        for(rint i=0;i<n;i++) a[i]=a[i]*b[i]%Mod;
        op=0,NTT(a);
        ll Inv=qpow(n,Mod-2);
        for(rint i=1;i<=n_;i++) a[i]=a[i]*Inv%Mod*fac[i]%Mod;
        for(rint i=1;i<=n_;i++) ans^=i*a[i];
        printf("%lld",ans);
    }
    
  • 相关阅读:
    重拾安卓_01_安卓开发环境搭建(eclipse)
    重拾安卓_01_安卓开发环境搭建(android studio)
    【BZOJ】1038: [ZJOI2008]瞭望塔
    【BZOJ】2178: 圆的面积并
    【UR #4】元旦三侠的游戏(博弈论+记忆化)
    【BZOJ】1027: [JSOI2007]合金(凸包+floyd)
    【POJ】1151 Atlantis(线段树)
    【POJ】1228 Grandpa's Estate(凸包)
    【POJ】1556 The Doors(计算几何基础+spfa)
    【POJ】1113 Wall(凸包)
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14402882.html
Copyright © 2011-2022 走看看