F. Scalar Queries

link:https://codeforces.com/contest/1167/problem/F

题意:

已知一个序列a
序列a下标l到r的所有元素从小到大排序的新序列为b1 b2 b3...bm
那么f(l,r)=b11+b22+b33+...+bmm
求序列a所有可能的f(l,r)的和(l<=r)
数据大小:1<=n<=5e5,1<=ai<=1e9

分析:

已知一个序列a: a1 a2 a3 a4...an
可以分别考虑每个数在所有区间所做的贡献,再求和
现在考虑的数为ai:
假设aj到ai之间有bj个小于ai的数,得到一个新序列b:
b1 b2 b3 b4.。.bi-1 0 bi+1...bn
假设l为选定的区间左端点的下标,r为选定的区间右端点的下标
那么ai的排名就是:ai左边小于ai的数个数+ai右边小于ai的数个数+1
也就是bl+br+1

那我们现在要求的就是所有区间的ai的排名求和,也就是所有的bl+br+1
不难得出公式:
所有排名的和=(b1+b2+b3+..bi)(n-i+1)+(b(i+1)+b(i+2)+...+bn)i+i*(n-i+1)

b1+b2+b3+..bi怎么求?
实际上这就是ai左边所有小于ai的数的下标之和,右边也同理(右边的下标也反过来看,
也就是n-i+1)
这里就可以用树状数组来维护,由于a[i]有1e9,所以需要离散化

时间复杂度为 o(nlogn)

代码:

#include<iostream>  
#include<cstring>  
#include<algorithm>  
#include<string>  
#include<vector>  
#include<map>  
using namespace std;  
const int N = 5e5+5,mod=1e9+7;  
#define int long long  
int n;  
int a[N],b[N];  
int sa[N],sb[N];  
int tr[N];  
map<int,int> mp;  
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;  
}  
  
int sum(int x){  
    int res = 0;  
    for (int i = x; i; i -= lowbit(i)) res += tr[i];  
    return res;  
}  
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];  
    memcpy(b,a,sizeof a);  
    sort(b+1,b+1+n);  
    int m=unique(b+1,b+1+n)-(b+1);  
    for(int i=1;i<=m;i++)mp[b[i]]=i;  
    for(int i=1;i<=n;i++){  
        add(mp[a[i]],i);  
        sa[i]=sum(mp[a[i]]-1);  
    }  
    memset(tr,0,sizeof tr);  
    for(int i=n;i>=1;i--){  
        add(mp[a[i]],n-i+1);  
        sb[i]=sum(mp[a[i]]-1);  
    }
    int res=0;  
    for(int i=1;i<=n;i++){
        res=(res+a[i]*(((n-i+1)*sa[i]+i*sb[i]+i*(n-i+1))%mod))%mod;  
    }
    cout<<res<<endl;
    return 0;  
}
posted @   lxllxs  阅读(12)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示