「PMOI-1」发怒

Solution

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

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

\[Ans(t)=\sum_{\omega \in \Omega} X(\omega)^p Pr(\omega)=\sum_{i=0}^t \binom{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!} \times \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);
}
posted @ 2021-02-14 22:32  Kreap  阅读(61)  评论(0编辑  收藏  举报