F. Scalar Queries

lxllxs發表於2024-05-28

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;  
}

相關文章