「PMOI-1」发怒
Link
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);
}