ABC353C Sigma Problem 题解

ABC353C Sigma Problem 题解

题目链接:AT

题目中的两个求和符号 i=1N1j=i+1N 实际上是在枚举所有的有序数对 (i,j)。而有序数对的个数 N(N1)/2=O(N2),真的去枚举所有数对肯定会 T。这时应该考虑去拆贡献,求出每个 Ai 对答案的贡献。

这道题的一个要点是要注意到题目中 Ai<108。也就是说,对于任意的 Ai,Aj,要么 Ai+Aj<108,此时有 f(Ai,Aj)=Ai+Aj;要么 108Ai+Aj<2×108,此时有 f(Ai,Aj)=Ai+Aj108

现在暂时不考虑第二种情况。这时所求的答案实际上就是枚举所有有序数对 (i,j),求和 Ai+Aj。因为每个 Ai 恰好出现在 N1 个数对中,所以此时的答案是 (N1)i=1NAi​。

(为什么每个 Ai 恰好出现在 N1 个数对中?原因十分简单:因为我们枚举了所有的有序数对,所以每个 Ai 一定和除了它本身之外的所有 N1 个元素都“配对”过一次,因此就出现在 N1 个数对中。当然,因为是有序数对,可能 Ai 有时是数对的第一个元素,有时是数对的第二个元素,但这显然不影响答案。)

如果考虑第二种情况,最终的答案就要减去若干个 108。具体减去多少个呢?对于某个 Ai,找出所有满足 Ai+Aj108j>ij 的个数,那么 Ai 就对答案贡献了这么多个 108。(这里限定 j>i 是因为题目中要求有序数对,不这么限定会导致重复计算。)于是可以先把 A 数组排序,对于某个 Ai,就可以二分查找出第一个满足Ai+Aj108j>ij0,于是满足条件的 j 的总数就是 Nj0+1

(为什么排序不会改变答案?要点在于题目中的 f(x,y) 函数满足“交换律”,或者说 f(x,y)=f(y,x),所以可以随意调换数组元素的顺序而不改变答案。与之区分的是本场比赛的 D 题,那道题和本题很像,都是枚举所有的有序数对 (i,j)​,然后求值某个二元函数的函数值的和。但 D 题的函数不满足这种“交换律”,所以不能先排序再求和。)

综上,我们先求出所有 Ai 的和的 N1 倍,再枚举所有的 Ai,找出应该减去多少个 108 即可。时间复杂度 O(NlogN),瓶颈在排序和二分查找。

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
constexpr int MAXN = 3e5 + 10;
constexpr ll MOD = 1e8;
int n;
ll a[MAXN], ans, cnt;

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i], ans += (n-1) * a[i];
	sort(a + 1, a + n + 1);
	for(int i = 1; i < n; i++)
	{
		ll x = MOD - a[i];
		int pos = lower_bound(a + i + 1, a + n + 1, x) - a; // 注意这里是从 a[i+1] 开始找的,这样能确保不会重复计算
		cnt += n - pos + 1;
	}
	ans -= cnt * MOD;
	cout << ans << endl;
	return 0;
}

提交记录

posted @   DengStar  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示