1、任意两个节点 i,j (i < j)
2、有 Ai <= Aj
3、那么:点对(i, j)对答案的贡献为( 2^(j - i - 1) )
综上所述:每个点的贡献与前面所有小于等于其节点到这个点距离和有关系(非线性)
观察 3 的式子之后发现若以 2^(i+1) 表示第 i 个点的价值,那么答案就是当前点用 2^j 表示后分别除上
前方所有的符合条件节点的价值之后的和。
关于除法,我们可以通过转化逆元处理出来由通过提取公因子 2^j 而将原式转化为加法,故本题可以用
树状数组处理前缀和解决。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define _for(i, a, b) for(int i = (a); i <= (b); i ++)
int mod = 998244353;
int n, m;
int a[300009], b[300009];
map<int, int> ma;
ll c[300009];
void init() {
int p = mod - 2;
ll ans = 1, x = 2;
while(p) { /// 求 2 的逆元
if(p & 1) ans = ans * x % mod;
x = x * x % mod; p >>= 1;
}
c[0] = 1; c[1] = ans;
_for(i, 2, n + 1) {
c[i] = 1ll * ans * c[i - 1] % mod; /// 预处理所有的 2 次幂逆元
}
}
ll tr[300009]; /// 树状数组
void add(int x, int d) {
while(x <= n) {
tr[x] += d; x += x & -x;
}
}
ll find(int x) {
ll ans = 0;
while(x) {
ans += tr[x]; x -= x & -x;
}
return ans % mod;
}
int main() {
cin >> n;
init();
_for(i, 1, n) cin >> a[i];
_for(i, 1, n) b[i] = a[i];
sort(b + 1, b + 1 + n); int tot = 0;
_for(i, 1, n) {
if(b[i] != b[i - 1]) ma[b[i]] = ++ tot; /// 离散化
}
ll ans = 0, p = 2;
_for(i, 1, n) {
ans += find(ma[a[i]]) * p % mod;
p = p * 2 % mod;
add(ma[a[i]], c[i + 1]);
}
cout << ans % mod;
return 0;
}
本题涉及知识点:树状数组,离散化