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