E - LEQ
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const ll mod=998244353;
struct bt{
int N;
vector<ll>bit;
bt(int n):N(n){bit.resize(N+1,0);
}ll ad(ll x,ll y){
return (x+y)%mod;
}void add(int x,ll a){
x++;
for(x;x<=N;x+=(x&-x))bit[x]=ad(bit[x],a);
}ll sum(int x){
x++;
ll ret=0;
for(x;x>0;x-=(x&-x))ret=ad(ret,bit[x]);
return ret;
}
};
ll modpow(ll x, ll y){
ll ret = 1;
while(0 < y){
if(y & 1){
ret *= x;
ret %= mod;
}
x *= x;
x %= mod;
y >>= 1;
}
return ret;
}
int comp(vector<int>&a){
map<int,int>me;
for(auto p:a)me[p]=0;
int sz=0;
for(auto &p:me)p.second=sz++;
for(auto &p:a)p=me[p];
return sz;
}
int main(){
const ll div=modpow(2,mod-2);
int N;cin>>N;
vector<int>a(N);
for(int i=0;i<N;i++)cin>>a[i];
int n=comp(a);
bt bit(n);
ll ans=0;
for(int i=0;i<N;i++){
ans+=bit.sum(a[i])*modpow(2,i);
ans%=mod;
bit.add(a[i],modpow(div,i+1));
}
cout<<ans;
}
思路
-------------------- 核心公式 1 --------------------
bit.sum(a[j]) = 所有 i<j 且 A[i] ≤ A[j] 的 (1/2^(i+1)) 之和
乘上 2^j 就等于题解中的 B_j × 2^(j-1)
对应题解:ans += B_j × 2^(j-1)
ans = (ans + bit.sum(a[j]) * modpow(2, j)) % mod;
-------------------- 核心公式 2 --------------------
把当前位置 j 加入树状数组
存入的值:1 / 2^(j+1)
对应题解:维护 1/2^i
bit.add(a[j], modpow(div, j + 1));
因为题目需要: 对每个 j,求左边 i<j 且 A[i]≤A[j] 的权值和, 还要动态插入数值。
这种**“前缀查询 + 单点更新 + 按值大小统计”**的操作, 树状数组是最优选择,复杂度 (O(N\log N)) 能过 3e5。