暴力复杂度达到O(n2),所以必须另辟蹊径。
由于带绝对值所以我的思路是分类讨论。
考虑序列中的某一个数j,假设大于等于1000-a[j]的数共有m个,假设第i个这样的数为
a
z
i
a_{z_{i}}
azi,则这部分的和为
a
j
+
a
z
1
−
1000
+
a
j
+
a
z
2
−
1000
+
.
.
.
+
a
j
+
a
z
m
−
1000
a_j+a_{z_{1}}-1000+a_j+a_{z_{2}}-1000+...+a_j+a_{z_{m}}-1000
aj+az1−1000+aj+az2−1000+...+aj+azm−1000
=
m
a
j
−
1000
m
+
∑
i
=
1
m
a
z
i
=ma_j-1000m+\sum \limits_{i=1}^{m}a_{z_{i}}
=maj−1000m+i=1∑mazi
同样,另一部分(假设为
a
f
i
a_{f_{i}}
afi)的和也可导出一个公式,两部分相加得到
结果=
∑
j
=
1
n
[
(
2
m
−
(
n
+
1
−
j
)
)
(
a
j
−
1000
)
+
∑
a
z
i
−
∑
a
f
i
]
\sum \limits_{j=1}^n[(2m-(n+1-j))(a_j-1000)+\sum a_{z_{i}}-\sum a_{f_i}]
j=1∑n[(2m−(n+1−j))(aj−1000)+∑azi−∑afi]
试验发现排序后结果不变(考场上没发现这个就没做出来……),所以只要对原序列排序、求前缀和,再利用二分即可。
实现如下:
llong res=0;
sort(a+1,a+n+1);
for(int i=1; i<=n; i++) sum[i]=sum[i-1]+a[i];
sum[n+1]=sum[n];
for(int i=1; i<=n; i++) {
int cnt=n+1-i;
int f=lower_bound(a+i,a+n+1,1000-a[i])-a; //找到第一个大于等于val的位置
int m=n+1-f; //和-1000后大于等于0的数字个数
res+=(2*m-cnt)*(a[i]-1000)+(sum[n]-sum[f-1])-(sum[f-1]-sum[i-1]);
}