GoldSpade
2024-11-17 10:40:46
纪念一个因打游戏而错过的水题。
给定长为
回忆使用
题目中只选取了一个长度为
求原序列的逆序对数,记为
求某个长为
两个子问题的解决方案如下:
归并排序或
已知原序列是一个排列,因此不需要担心元素相等的情况,于是这个区间的元素可以等价为一个排列。你可以通过如下方式得知长为
OEIS,打表找规律。
直接推,每一个数对
变化量
使用任意方式求出排列的逆序对数,加入答案。
使用
答案加上
输出答案。时间复杂度
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, r, l) for (int i = r; i >= l; i--)
#define cnt1(x) __builtin_popcount(x)
#define int long long
using namespace std;
const int N = 2e5+5, M = 2e6+5, mod = 998244353;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
int n, K, a[N], ans, now, c[N];
// now 表示滑动到某个区间的逆序对数
inline void add(int x, int v) {
for (; x <= n; x += x & -x) c[x] += v;
}
inline int ask(int x) {
int res = 0;
for (; x; x -= x & -x) res += c[x];
return res;
}
inline int qpow(int a, int b) {
int res = 1;
for (; b; b >>= 1) {
if (b & 1) res = a * res % mod;
a = a * a % mod;
}
return res;
}
signed main() {
FASTIO;
cin >> n >> K;
rep(i, 1, n) cin >> a[i];
rep(i, 1, n) {
ans += i-1-ask(a[i]);
add(a[i], 1);
}// 求最初逆序对,使用的是 BIT
memset(c, 0, sizeof c);
int inv = qpow(4, mod-2), inv2 = qpow(n-K+1, mod-2);
rep(i, 1, n) {
if (i > K) now -= ask(a[i-K]-1), add(a[i-K],-1);// 删去超出区间的元素及其贡献
now += ask(n)-ask(a[i]);// 加入新元素的贡献
if (i >= K) ans = (ans+(K*(K-1)%mod*inv%mod-now%mod+mod)%mod*inv2)%mod;
add(a[i], 1);// 加入新元素
}
cout << ans;
return 0;
}