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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步