[ARC228C] Partially Sort
Genius_Star · · 题解
或许更好的阅读体验。
思路:
显然拆贡献去做,考虑一对原来逆序对的贡献
设没有被选的那个是
所以对于
于是问题变为快速算:
考虑换元
那么
然后考虑:
现在你发现难点在于
这个 trick 和 [ARC230A] Meeting on Tree 完全一致,不知道为什么这么近的时间出同一个何意味???而且一个 900,一个 3000!!!
于是:
你发现这是一个组合数后缀和的问题,可以写成前缀和的形式好看点:
上指标每次询问都不固定,于是直接暴力莫队去维护即可。
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
const int N = 4e5 + 10, mod = 998244353, inv2 = (mod + 1) >> 1;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
inline void getadd(int &x, int y){
x = (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline int add(int x, int y){
return (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline void getdec(int &x, int y){
x = (x < y) ? (x - y + mod) : (x - y);
}
inline int dec(int x, int y){
return (x < y) ? (x - y + mod) : (x - y);
}
inline int qpow(int a, int b){
int ans = 1;
while(b){
if(b & 1)
ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ans;
}
int n, ans, t, cnt, now;
int siz[N], fac[N], ifac[N], p2[N], p[N], a[N], A[N];
int pz[N], Ans[N];
struct Ques{
int l, r, w, id;
inline bool operator<(const Ques&rhs)const{
if(A[l] ^ A[rhs.l])
return A[l] < A[rhs.l];
return r < rhs.r;
}
}Q[N];
inline void upd(int x, int v){
for(int i = x; i <= n; i += lowbit(i))
a[i] += v;
}
inline int ask(int x){
int sum = 0;
for(int i = x; i; i -= lowbit(i))
sum += a[i];
return sum;
}
inline void init(){
fac[0] = fac[1] = p2[0] = 1, p2[1] = 2;
for(int i = 2; i < N; ++i){
fac[i] = 1ll * fac[i - 1] * i % mod;
p2[i] = 2ll * p2[i - 1] % mod;
}
ifac[N - 1] = qpow(fac[N - 1], mod - 2);
for(int i = N - 2; i >= 0; --i)
ifac[i] = 1ll * (i + 1) * ifac[i + 1] % mod;
}
inline int binom(int n, int m){
if(m > n || m < 0 || n < 0)
return 0;
return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
// inline int f(int n, int m){
// int s = 0, sum = 0;
// for(int k = 0; k <= n - 1; ++k)
// getadd(s, binom(n + m - 1, k));
// getdec(sum, 1ll * s * m % mod);
// getadd(s, binom(n + m - 1, n));
// getadd(sum, 1ll * s * n % mod);
// return sum;
// }
// inline int solve(int n, int m){
// return f(n, m) + f(m, n);
// }
inline void getqry(int n, int m, int id){
getadd(Ans[id], 1ll * n * binom(n + m - 1, n) % mod);
Q[++cnt] = {n + m - 1, n - 1, dec(n, m), id};
}
inline void getques(int n, int m, int id){
getqry(n, m, id);
getqry(m, n, id);
}
int main(){
init();
n = read();
for(int x = 1; x <= n; ++x){
p[x] = read();
int y = p[x] - 1, z = ask(p[x]);
pz[x] = z;
getques(x - 1 - z, y - z, x);
getadd(ans, 1ll * (x - 1 - z) * p2[n - 2] % mod);
// cerr << x << ' ' << y << ' ' << z << '\n';
// for(int a = 0; a < x; ++a)
// for(int b = 0; b <= y; ++b)
// for(int c = 0; c <= b; ++c)
// getadd(ans, 1ll * binom(z, c) * binom(y - z, b - c) % mod * binom(x - 1 - z, a - c) % mod % mod * abs(a - b) % mod);
upd(p[x], 1);
}
t = n / sqrt(cnt) + 1;
for(int i = 1; i <= n; ++i)
A[i] = (i - 1) / t + 1;
sort(Q + 1, Q + cnt + 1);
int l = 1, r = 1;
now = 2;
for(int i = 1; i <= cnt; ++i){
while(l < Q[i].l){
now = dec(2ll * now % mod, binom(l, r));
l++;
}
while(r > Q[i].r){
now = dec(now, binom(l, r));
r--;
}
while(l > Q[i].l){
--l;
now = 1ll * add(now, binom(l, r)) * inv2 % mod;
}
while(r < Q[i].r){
++r;
now = add(now, binom(l, r));
}
getadd(Ans[Q[i].id], 1ll * now * Q[i].w % mod);
}
for(int x = 1; x <= n; ++x){
int y = p[x] - 1, z = pz[x];
getadd(ans, 1ll * p2[n - x - (y - z) + z] * Ans[x] % mod);
}
write(ans);
return 0;
}