首页 > 其他分享 >ABC353C Sigma Problem 题解

ABC353C Sigma Problem 题解

时间:2024-05-12 12:19:01浏览次数:18  
标签:10 ABC353C int 题解 所有 枚举 答案 Problem 序数

ABC353C Sigma Problem 题解

题目链接:AT

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

这道题的一个要点是要注意到题目中 \(A_i \le 10^8\)。也就是说,对于任意的 \(A_i, A_j\),要么 \(A_i + A_j < 10^8\),此时有 \(f(A_i, A_j) = A_i + A_j\);要么 \(10^8 \le A_i + A_j < 2 \times 10^8\),此时有 \(f(A_i, A_j) = A_i + A_j - 10^8\)。

现在暂时不考虑第二种情况。这时所求的答案实际上就是枚举所有有序数对 \((i, j)\),求和 \(A_i + A_j\)。因为每个 \(A_i\) 恰好出现在 \(N-1\) 个数对中,所以此时的答案是 \((N-1) \sum_{i=1}^{N} A_i\)​。

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

如果考虑第二种情况,最终的答案就要减去若干个 \(10^8\)。具体减去多少个呢?对于某个 \(A_i\),找出所有满足 \(A_i + A_j \ge 10^8\) 且 \(j > i\) 的 \(j\) 的个数,那么答案就要减去这么多个 \(10^8\)。(这里限定 \(j > i\) 是因为题目中要求有序数对,不这么限定会导致重复计算。)于是可以先把 \(A\) 数组排序,对于某个 \(A_i\),就可以二分查找出第一个满足\(A_i + A_j \ge 10^8\) 且 \(j > i\) 的 \(j\),从而计算出所有满足的 \(j\) 的数量。

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

综上,我们先求出所有 \(A_i\) 的和的 \(N-1\) 倍,再枚举所有的 \(A_i\),找出应该减去多少个 \(10^8\) 即可。时间复杂度 \(O(N \log N)\),瓶颈在排序和二分查找。

代码:

#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;
}

提交记录

标签:10,ABC353C,int,题解,所有,枚举,答案,Problem,序数
From: https://www.cnblogs.com/dengstar/p/18187669

相关文章

  • C - Sigma Problem
    C-SigmaProblemhttps://atcoder.jp/contests/abc353/tasks/abc353_c 思路暴力TLE观察a1a2...an序列计算目标是,两两结合并并求模sum=sigma(ai+aj)%1e8ai,aj<=1e8ai+aj可能溢出,也可能不溢出于是我们考虑,统计所有溢出的个数。 对数组进行排序,......
  • 2024江苏省大学生程序设计大赛(JSCPC)热身赛题解(B)
    题目大意:求区间\([l,r]\)中有多少正整数满足\(\phi(\phi(n))=\phi(n)-1\),其中\(\phi\)为欧拉函数。解:设\(y=\phi(n)\),则上式变为\(\phi(y)=y-1\),易证\(y\)为质数(注意\(\phi(1)=1\),\(1\)与任何正整数都互质)。故原问题转化为求\([l,r]\)中有多少个正整数v满足\(\phi......
  • set 容器详解 附大根堆题解
    声明本文中题解部分内容大部分转载自@sonnety的这篇博客中,本文为为方便复习而写的结论类文章,读者可自行跳转至原文处阅读。PART1set什么是set——来源cppreference简言之,它就是一种存进去就可以自动按升序排列的特殊容器,通常的set还具有自动去重的功能。定义方......
  • 工作疑难问题解决4例
      记录一下工作上疑难问题解决:  一,方便的页面监控     前几天早上,负责的kettle抽取数据表的任务又报错了,早上看手机有4个未接报警电话,一看是人员表,原来昨天报表系统有个大的查询一直未查询完成,导致truncate这个人员表,无法活动meta的锁,后续执行抽取和计算的都报错......
  • U423621 [HDK - NRC] Sqen Paradox 题解
    题目描述及\(O(n^2)\)做法见这个设\(a_i\)表示以\(i\)为左端点,无重复元素的最长区间的左端点,这个直接拿双指针做就行。处理出来后,分类讨论,找\(\max(i-l+1,i-a_i+1)\),找\(i-l+1\)拿个桶维护一下左端点为\(i\)的右端点有那些就行,剩下的位置找最值即可,这个是RMQ。时间......
  • 工作疑难问题解决4例
      记录一下工作上疑难问题解决:  一,方便的页面监控     前几天早上,负责的kettle抽取数据表的任务又报错了,早上看手机有4个未接报警电话,一看是人员表,原来昨天报表系统有个大的查询一直未查询完成,导致truncate这个人员表,无法活动meta的锁,后续执行抽取和计算的都报错......
  • 第六届·2024 MindSpore 量子计算黑客松热身赛赛题解读
    第六届·2024MindSpore量子计算黑客松火热进行中。本次大赛由量子信息网络产业联盟主办,昇思MindSporeQuantum社区承办,多所高校和单位联合举办。开发者将全面体验全新一代通用量子计算框架MindSporeQuantum。热身赛为量子计算基础学习和编程演练。完成热身赛的前100名选手将有......
  • 题解
    #include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmain(){ intN,m;//N奖金m物品个数cin>>N>>m;N/=10;//由于所有的价格都是10的整倍数,所以可以均除10以简化运算复杂度intprice,priority,hasAttachme......
  • 题解:CF1956A Nene's Game
    这道题其实挺有意思,多测里面还套了个多测。思路就是用向量模拟删除过程,具体请看代码里的注释。#include<bits/stdc++.h>usingnamespacestd;intk,q,a[105];voidsolve(){ intn; cin>>n; vector<int>ve; for(inti=1;i<=n;i++)ve.push_back(i);//把每个人放到向量......
  • CF1385F Removing Leaves 题解
    看到题,感觉像树形DP,遂设计DP式子。\(dp_u\)表示以\(u\)为根的子树内最多能删多少次(不删\(u\))。那么每次子节点到父节点增加的贡献就是\(\lfloor\frac{子树大小为1的子节点个数}{k}\rfloor\)。得出式子\(dp_u=\sum_{v\inson_u}dp_v+(\sum_{v\inson_u}[dp_v\times......