1017 珂朵莉的数列 离散化 树状数组 逆序区间 贡献计算
链接:https://ac.nowcoder.com/acm/contest/26896/1017
来源:牛客网
题目描述
珂朵莉给了你一个序列,有n×(n+1)2\frac{n\times(n+1)}22n×(n+1)个子区间,求出她们各自的逆序对个数,然后加起来输出
输入描述:
第一行一个数 n 表示这个序列 a 的长度
之后一行 n 个数,第i个数表示ai
输出描述:
输出一行一个数表示答案
备注:
对于100%的数据,n <=
1000000 ,0 <= 序列中每个数 <= 1000000000
分析
由数据范围,肯定不能暴力,只能累计,计算贡献。
对于两个数a[i] 和 a[j] 它们的贡献是在以 [1,i] 为左端点 和以 [j,n] 为右端点的所有区间都有一个贡献,所以计算出前面的所有左端点的累计数量 乘上 (n-j+1)即可
值得注意的是数据范围1e6+10,不是1e5,lower_bound可以给数组用,找到它在数组中的位置,add(a[i],i) 要+i 才是所有左端点的累计数量。
//-------------------------代码---------------------------- #define int ll const int N = 1e6+10; int n,m; int a[N]; int sum[N]; int tr[N]; int lowbit(int x) { return x & -x; } void add(int x,int c) { for(int i = x;i<=N;i+=lowbit(i)) {tr[i] += c;} } ll query(ll x) { ll res = 0;for(int i = x;i;i-=lowbit(i)) res += tr[i];return res; } void build(int u,int l,int r) { } int b[N]; void print(__int128_t x) { if(x < 0) {putchar('-'),x = -x;} if(x > 9) print(x / 10); putchar(x % 10 + '0'); } void solve() { // cin>>n>>m; read(n); fo(i,1,n) { read(a[i]); b[i] = a[i]; } sort(b+1,b+1+n); fo(i,1,n) a[i] = lower_bound(b+1,b+1+n,a[i]) - b + 1; __int128_t res = 0; fo(i,1,n) { res += (query(N-3) - query(a[i])) * (n-i+1); add((a[i]),i); } print(res); } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------