ACL001E Shuffle Window

Arahc 11.0

题面

简化题意

给定一个排列 p1...np_{1...n} 和一个整数 KK,进行如下操作 nK+1n-K+1 次:

  • ii 次操作时,随机打乱 pi,pi+1,pi+2,,pi+K1p_{i},p_{i+1},p_{i+2},\cdots,p_{i+K-1} 这些数字。

求操作完成后序列逆序对数的期望,对 998244353998244353 取模。

n2×105n\leq 2\times10^5

题解

每次随机打乱一个区间长得很丑,我们发现相邻两个操作的区间是相邻的。考虑转化一下操作的形式:

  1. 初始时有一个空序列 aa 和一个集合 S={pi1iK}S = \{p_i | 1\leq i\leq K\}
  2. ii 次操作时,随机选择 SS 中的一个数字加入到 aa 序列的末尾,然后把 pi+Kp_{i+K} 加入到 SS 中。
  3. SS 中剩余的数字随机打乱,依次加入 aa 末尾。

于是我们可以求出 fi=max{0,iK}f_i = \max\{0,i-K\} 表示 pip_i 会在第几次操作中加入到 SS 内。下面考虑计算某两个数 pi,pjp_i,p_j 的相对位置改变的概率。不妨设 i<ji<j

当两个数都在 SS 内时,概率等价于 pjp_jpip_i 先选的概率,显然为 12\frac{1}{2}。而这两个数能同时出现在 SS 内的概率为 (K1K)fjfi(\frac{K-1}{K})^{f_{j}-f_{i}}。因此两数交换的概率为 12(K1K)fjfi\frac{1}{2}(\frac{K-1}{K})^{f_{j}-f_{i}}

于是我们先求出原序列有多少逆序对,再求出逆序对的期望变化量即可。前者一个 BIT 就可以了,求后者的关键在于对于满足 i<ji<jai>aja_{i}>a_{j}(或反过来)的下标数对 i,ji,j,求 (K1K)fjfi(\frac{K-1}{K})^{f_{j}-f_{i}} 的和。也是一个 BIT 就可以了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool Begin;
const int max_n=200005,mod=998244353,iv2=499122177;
inline int read(){
int x=0;bool w=0;char c=getchar();
while(c<'0' || c>'9') w|=c=='-',c=getchar();
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
}
inline int Plus(int &x,int y){return x=(x+y>=mod?x+y-mod:x+y);}
inline int Minu(int &x,int y){return x=(x<y?x-y+mod:x-y);}
inline int MOD(int x){return x>=mod?x-mod:x;}
inline int mi(int a,int p=mod-2){
int res=1;
while(p){
if(p&1) res=res*a%mod;
a=a*a%mod,p>>=1;
}
return res;
}

int n,K,P,a[max_n],ans;

struct BIT{
int a[max_n];
inline void add(int i,int x){
for(;i<=n;i+=i&-i) Plus(a[i],x);
}
inline int pre(int i){
int res=0;
for(;i;i-=i&-i) Plus(res,a[i]);
return res;
}
inline int ask(int l,int r){
return MOD(pre(r)-pre(l-1)+mod);
}
}bit1,bit2;

int mip[max_n],inv[max_n],f[max_n];

bool End;
#define File ""
signed main(){
// #ifndef ONLINE_JUDGE
// freopen(File ".in","r",stdin);
// freopen(File ".out","w",stdout);
// #endif
n=read(),K=read(),P=(K-1)*mi(K)%mod;
mip[0]=inv[0]=1;
for(int i=1;i<=n;++i)
mip[i]=mip[i-1]*P%mod;
inv[n]=mi(mip[n]);
for(int i=n-1,ip=mi(P);i;--i)
inv[i]=inv[i+1]*P%mod;
iota(f+K+1,f+n+1,1);
for(int i=1;i<=n;++i){
a[i]=read();
ans=MOD((ans+mip[f[i]]*bit1.pre(a[i])-mip[f[i]]*bit1.ask(a[i],n)+bit2.ask(a[i],n))%mod+mod);
bit1.add(a[i],iv2*inv[f[i]]%mod);
bit2.add(a[i],1);
}
write(ans);
return 0;
}
  • 标题: ACL001E Shuffle Window
  • 作者: Arahc
  • 创建于 : 2022-11-06 08:00:00
  • 更新于 : 2023-03-15 02:53:34
  • 链接: https://arahc.github.io/2022/11/06/【题解】ACL001E-Shuffle-Window/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
ACL001E Shuffle Window