这题断断续续做了几次了。。。思路有没有问题? 用f1,f2,f3分别存储x,y,x*y的和, 需要调用的时候差分求区间和就行了;主要还是公式什么的有没有问题。。。
公式(类比归并排序): 对于已经把v从小到大排好的序列,按照x(在这里是tot数组)的大小来进行插入 每插入一次,分为左区间和右区间两种情况 分别按照题意数学推导即可(处理数据是为了保证符合题意的绝对值以及max)
#include<bits/stdc++.h>
#define maxn 600000
using namespace std;
int tot[maxn],n,x[maxn],v[maxn],k[maxn],flag[maxn];
unsigned long long f1[maxn],f2[maxn],f3[maxn];
unsigned long long ans;
vector<int> a[maxn];
void test1(){//调试用
for (int i=1;i<=n;i++) cout<<f1[i]<<" ";
cout<<endl;
for (int i=1;i<=n;i++) cout<<f2[i]<<" ";
cout<<endl;
for (int i=1;i<=n;i++) cout<<f3[i]<<" ";
cout<<endl;
}
void solve(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
solve(l,mid);solve(mid+1,r);
for (int ii=l,i=l,j=mid+1;ii<=r;ii++){
if (i==mid+1){
// cout<<"加入j一次;"<<(i-l)*v[j]*tot[j]-v[j]*(f1[i-1]-f1[l-1])<<endl;
ans+=(i-l)*v[j]*tot[j]-v[j]*(f1[i-1]-f1[l-1]);
k[ii]=tot[j++];
}
else if (j==r+1){
// cout<<"加入i一次;"<<tot[i]*(f2[j-1]-f2[mid])-(f3[j-1]-f3[mid])<<endl;
ans+=tot[i]*(f2[j-1]-f2[mid])-(f3[j-1]-f3[mid]);
k[ii]=tot[i++];
}
else if (tot[i]<=tot[j]){
// cout<<"加入i一次;"<<tot[i]*(f2[j-1]-f2[mid])-(f3[j-1]-f3[mid])<<endl;
ans+=tot[i]*(f2[j-1]-f2[mid])-(f3[j-1]-f3[mid]);
k[ii]=tot[i++];
}
else{
// cout<<"加入j一次;"<<(i-l)*v[j]*tot[j]-v[j]*(f1[i-1]-f1[l-1])<<endl;
ans+=(i-l)*v[j]*tot[j]-v[j]*(f1[i-1]-f1[l-1]);
k[ii]=tot[j++];
}
}
for (int i=l;i<=r;i++) tot[i]=k[i];
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&v[i],&x[i]);
a[v[i]].push_back(x[i]);
}
sort(v,v+n+1);
int tem=1;
for (int i=1;i<=n;i++){
if (!flag[v[i]]){
flag[v[i]]=1;
for (int j=0;j<a[v[i]].size();j++)
tot[tem++]=a[v[i]][j];
}
}
tem--;
for (int i=1;i<=n;i++){
f1[i]=f1[i-1]+tot[i];
f2[i]=f2[i-1]+v[i];
f3[i]=f3[i-1]+v[i]*tot[i];
}//f1:x f2:y f3:x*y
// test1();
solve(1,n);
printf("%d",ans);
}