20201004

T1

老王雪

1.1 \(n, m ≤ 10\)

每次修改完后,枚举所有可能的\(n!\)种配对方案,计算最大、最小值。
时间复杂度\(O(m ∗ n!)\)。期望得分:10.

1.2 \(n, m ≤ 2000\)

注意到最小的质量之和一定是将\(p\)\(v\)分别按从小到大和从大到小排序,并将对应数字分别配对。最大的质量之和是将\(p\)\(v\)均按从小到大排序,将对应数字分别配对。每次修改后在有序的数组中二分修改的数字,则只需要将该数字的位置进行调整,就能得到有序的数组。每次修改完后\(O(n)\)统计答案。
时间复杂度\(O(nm)\)。期望得分:55.

1.3

参照1.2的做法,注意到\(|delta| = 1\),若\(delta = 1\),则找到修改的数字在有序数组中最后一次出
现的位置,将该位置的数\(+1\),得到的仍然是一个有序的数组,只要修改这一位对答案的贡献即可。同
理当\(delta = −1\)时,找到修改的数在有序数组中第一次出现的位置,令该位置上的数\(−1\)并维护答案。
时间复杂度\(O(n log n)\)。期望得分:100.
总体来说这道题的核心是排序不等式,虽然名字十分的高大上,但实际上就是很好感性的一个结论,两个数组,保证\(max[i]*max[j],i,j\)依次递减,则这两个数组的积一定为满足\(max\).

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;

#define LL long long

const int N = 300005;

int n, m, a[N], b[N], p[N], q[N];
LL ans1, ans2;

void solve(int * a, int * b, int w, int del)
{
	if (del == 1)
	{
		int p = upper_bound(a + 1, a + n + 1, w) - a - 1;
		a[p]++;
		ans1 += b[n - p + 1]; ans2 += b[p];
	}
	else
	{
		int p = lower_bound(a + 1, a + n + 1, w) - a;
		a[p]--;
		ans1 -= b[n - p + 1]; ans2 -= b[p];
	}
}

int main()
{
	freopen("chemist.in", "r", stdin);
	freopen("chemist.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
	scanf("%d", &a[i]), p[i] = a[i];
	}
	for (int i = 1; i <= n; i++) {
	scanf("%d", &b[i]), q[i] = b[i];
	}
	sort(a + 1, a + n + 1);
	sort(b + 1, b + n + 1);
	for (int i = 1; i <= n; i++) ans1 += (LL)a[i] * b[n - i + 1], ans2 += (LL)a[i] * b[i];
	printf("%lld %lld\n", ans1, ans2);
	while (m--)
	{
		int ty, x, del; 
		scanf("%d%d%d", &ty, &x, &del);
		if (ty == 1) solve(a, b, p[x], del), p[x] += del;
		else solve(b, a, q[x], del), q[x] += del;
		printf("%lld %lld\n", ans1, ans2);
	}
	return 0;
}

T2

posted on 2020-10-04 15:14  fishsit  阅读(106)  评论(0编辑  收藏  举报

导航