题意简述
给定 n ( < = 2 e 4 ) n(<=2e4) n(<=2e4),和 n n n个奶牛。每个奶牛有两个值, v ( 每 个 < = 2 e 4 ) v(每个<=2e4) v(每个<=2e4), x i ( 每 个 < = 2 e 4 ) x_i(每个<=2e4) xi(每个<=2e4)。求对于所有的奶牛 ( a , b ) ( 1 < = a < b < = n ) (a,b)(1<=a<b<=n) (a,b)(1<=a<b<=n), m a x ( v a , v b ) ∗ ( ∣ x a − x b ∣ ) max(v_a,v_b)*(|x_a-x_b|) max(va,vb)∗(∣xa−xb∣)的值的和。
思路
这题看到要求的式子里有一个 m a x max max,一个绝对值,第一眼看到肯定是没有思路的。但是我们要想想,最大值怎么拆?绝对值怎么拆?
最大值是好做的,我们只要把 n n n个奶牛按 v v v值排序就好做了。枚举 i i i,考虑 [ 1 , i − 1 ] [1,i-1] [1,i−1]之间的答案,由于是排好序的,前面的 v v v值肯定不会超过 v i v_i vi,那么取 m a x max max就一定是 v i v_i vi了。
那么绝对值呢?通常我们要求两个数相减的绝对值的时候,要讨论两个数哪个大。还是枚举 i i i,讨论:
-
x i x_i xi是较大的数。
此时,对于前面所有的 j j j满足: x j < = x i x_j<=x_i xj<=xi,要求和
( x i − x j ) (x_i-x_j) (xi−xj),乘以 v i v_i vi,就是对答案的贡献了。也就是 ∑ j = 1 i − 1 [ x j < = x i ] ( x i − x j ) \sum\limits_{j=1}^{i-1}[x_j<=x_i](x_i-x_j) j=1∑i−1[xj<=xi](xi−xj)。然后我们发现 x i x_i xi是不变的数,珂以提出来。但是系数呢?就是 [ 1 , i − 1 ] [1,i-1] [1,i−1]中满足 x j < = x i x_j<=x_i xj<=xi的个数。设其为 C C C(xk)。原式化为:
C ∗ x i − ∑ j = 1 i − 1 [ x j < = x i ] x j C*x_i-\sum\limits_{j=1}^{i-1}[x_j<=x_i]x_j C∗xi−j=1∑i−1[xj<=xi]xj。那么此时我们发现,还要求一个东西,就是 ∑ j = 1 i − 1 [ x j < = x i ] x j \sum\limits_{j=1}^{i-1}[x_j<=x_i]x_j j=1∑i−1[xj<=xi]xj。设其为 S S S。( C C C和 S S S的求法过会再说,先讨论) -
x i x_i xi是较小的数
此时,对于前面所有的 j j j满足: x j > x i x_j>x_i xj>xi(为了避免和1.重复,这里不取等),求和:
( x j − x i ) (x_j-x_i) (xj−xi),乘以 v i v_i vi,就是贡献。也就是 ∑ j = 1 i − 1 [ x j > x i ] ( x j − x i ) \sum\limits_{j=1}^{i-1}[x_j>x_i](x_j-x_i) j=1∑i−1[xj>xi](xj−xi)。照例还是提 x i x_i xi,但是系数呢?不会又要再设一个数出来吧。。。
别担心,完全不用。前 i − 1 i-1 i−1个数中,要么就是 x j > x i x_j>x_i xj>xi,要么就是 x j < = x i x_j<=x_i xj<=xi。我们知道了 x j < = x i x_j<=x_i xj<=xi的个数,拿总数 i − 1 i-1 i−1去减掉它,就是满足 x j > x i x_j>x_i xj>xi的个数了,即 ( i − 1 − C ) (i-1-C) (i−1−C)个。
类似的思路,式子变为: ∑ j = 1 i − 1 [ x j > x i ] x j − ( i − 1 − C ) ∗ x \sum\limits_{j=1}^{i-1}[x_j>x_i]x_j-(i-1-C)*x j=1∑i−1[xj>xi]xj−(i−1−C)∗x。现在我们要求 ∑ j = 1 i − 1 [ x j > x i ] x j \sum\limits_{j=1}^{i-1}[x_j>x_i]x_j j=1∑i−1[xj>xi]xj,如何求呢?类似得到 i − 1 − C i-1-C i−1−C的思路,其实我们只要用前 i − 1 i-1 i−1个数的前缀和,减去 S S S,就是这里的这个东西了。我们一边枚举 i i i,一边记录当前 ( 1 , i − 1 ) (1,i-1) (1,i−1)的和。设这个和为 a l l all all,那么此时的式子就是: ( a l l − S ) − ( i − 1 − C ) ∗ x (all-S)-(i-1-C)*x (all−S)−(i−1−C)∗x。
现在差不多知道式子了。我们很清楚 a l l all all的求法,就是边枚举边记录。问题来了:怎么求 C C C和 S S S?
维护一个权值树状数组 T c , T s Tc,Ts Tc,Ts, T c [ x ] Tc[x] Tc[x]表示:满足 a i = x a_i=x ai=x的数有多少个。 T s [ x ] Ts[x] Ts[x]表示 a i = x a_i=x ai=x的数的 x x x值和。然后 C C C就是 T c [ 1 ] + T c [ 2 ] . . . + T c [ x i ] Tc[1]+Tc[2]...+Tc[x_i] Tc[1]+Tc[2]...+Tc[xi], S S S就是 T s [ 1 ] + T s [ 2 ] . . . + T s [ x i ] Ts[1]+Ts[2]...+Ts[x_i] Ts[1]+Ts[2]...+Ts[xi]。(由于是 < = <= <=,珂以取到 x i x_i xi。)我们发现是求前缀和的工作,珂以用树状数组快速求出。
然后要讲的就是次序问题。首先我们要先作询问操作,求出 S , C S,C S,C的值,统计答案,然后再记录 T c , T s Tc,Ts Tc,Ts和 a l l all all的值。尤其是 a l l all all,一定要写在后面,这样才能保证我们前面再调用的时候还只有前 i − 1 i-1 i−1个数的和。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
namespace Flandle_Scarlet
{
#define int long long
#define N 200100
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
struct node
{
int v,x;
}a[N];
bool cmp_v(node a,node b){return a.v<b.v;}
int n;
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void Input()
{
R1(n);
for(int i=1;i<=n;++i)
{
int v,x;
R1(v),R1(x);
a[i]=(node){v,x};
}
}
class BIT
{
public:
int tree[N];
int len;
void BuildTree(int _len)
{
len=_len;
FK(tree);
}
void Add(int pos,int val)
{
for(int i=pos;i<=len;i+=(i&(-i)))
{
tree[i]+=val;
}
}
int Query(int pos)
{
int ans=0;
for(int i=pos;i>0;i-=(i&(-i)))
{
ans+=tree[i];
}
return ans;
}
}Tc,Ts;
void Soviet()
{
Tc.BuildTree(200000);
Ts.BuildTree(200000);
sort(a+1,a+n+1,cmp_v);
int ans=0;
int all=0;
for(int i=1;i<=n;++i)
{
int x=a[i].x,v=a[i].v;
int lcnt=Tc.Query(x),lsum=Ts.Query(x);
ans+=(x*lcnt-lsum)*a[i].v;
ans+=((all-lsum)-(i-1-lcnt)*x)*a[i].v;
Tc.Add(x,1);
Ts.Add(x,x);
all+=a[i].x;
}
printf("%lld\n",ans);
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
Input();
Soviet();
}
#undef int //long long
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}

本文探讨了一道经典的算法题目,涉及对奶牛的价值和位置进行排序和计算,通过使用树状数组来优化求解过程,实现高效计算所有奶牛对的最大值与距离乘积之和。
620

被折叠的 条评论
为什么被折叠?



