ABC实在是没什么好说的,但是D题真的太妙了,详细的说一下吧
首先思路是对于a相等的分类,假设有n个,则肯定要把n-1个都增加,因为a都是相等的,所以肯定是增加t小的分类,也就是说每次都能处理一个分类,复杂度是O(n^2),这个思路很好写,优先队列随便搞一下就行了,但是题目中N = 2 * 1e5,n^2肯定是不行的,然后就是这个很巧妙的方法了,cf官方的题解我没看懂...有点尴尬,它也没给标程,但是cf的题解好像不是这个方法
看了网上用并查集的方法,首先以t为关键字从大到小排序,然后用并查集维护当前这个应该加到哪个数字,因为是从大到小排序,所以加的数字越来越大,假设排序后是1112,首先第一次是1,不用加,把1连到2,第二次把1连到3,第三次把1连到4,然后最妙的事情就是,2这时候因为1连了2,所以这时候我们可以知道2需要连到4,因为每个数字一层一层的往上加,在合并的过程中就合并在一起了,所以保证了正确性。
#include <cstdio> #include <algorithm> #include <map> using namespace std; const int N = 200010; struct news{ int a, t; bool operator < (const news &o) const{ return t > o.t; } } num[N]; map < int, int > fa; int find(int a) { return (fa[a] == 0) ? a : (fa[a] = find(fa[a])); } inline void merge(int a, int b) { int f = find(b); if (f != a) fa[a] = f; } int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &num[i].a); for (int i = 0; i < n; i++) scanf("%d", &num[i].t); long long ans = 0; sort(num, num + n); for (int i = 0; i < n; i++) { int f = find(num[i].a); if (f == num[i].a) { merge(f, f + 1); } else { merge(f, f + 1); ans = ans + 1ll * (f - num[i].a) * num[i].t; } } printf("%lld ", ans); return 0; }
------------恢复内容结束------------