[Codeforces 1070F]Debate(贪心)

Address

洛谷 RemoteJudge
Codeforces 1070F

Meaning

  • Alice 和 Bob 参加选举
  • n n 个投票人,第 i i 个人有两个属性 s i s_i a i a_i
  • 对于第 i i 个人, s i s_i 是一个长度为 2 2 01 01
  • s i = 00 s_i=00 表示第 i i 个人不支持 Alice 和 Bob
  • s i = 01 s_i=01 表示第 i i 个人不支持 Alice 但支持 Bob
  • s i = 10 s_i=10 表示第 i i 个人支持 Alice 但不支持 Bob
  • s i = 11 s_i=11 表示第 i i 个人支持 Alice 和 Bob
  • i i 个人的影响力为 a i a_i
  • 现在要从中选出一些人,满足下面 2 2 个条件
  • (1)选出的人中,支持 Alice 的人数的 2 2 倍大于或等于选出的人数
  • (2)选出的人中,支持 Bob 的人数的 2 2 倍大于或等于选出的人数
  • 求选出的人的影响力之和的最大值

Solution

  • 考虑把所有投票人按照 s i s_i 分开,显然在最优方案中 s i = 11 s_i=11 的投票人必须被选出
  • 然后重点对 00 00 01 01 10 10 进行分析
  • 一个结论:在最优方案中,所有 s i = 01 s_i=01 的投票人全部被选出,或者所有 s i = 10 s_i=10 的投票人全部被选出
  • 证明:如果有一种合法方案,有 x x s i = 01 s_i=01 的投票人没被选出,有 y y s i = 10 s_i=10 的投票人没被选出
  • 那么再选 min ( x , y ) \min(x,y) s i = 01 s_i=01 的投票人和 min ( x , y ) \min(x,y) s i = 10 s_i=10 的投票人则显然还是合法
  • 下面对 s i = 01 s_i=01 的投票人全部被选出的情况进行讨论( s i = 10 s_i=10 的投票人全部被选出的情况同理)
  • 先把 s i = 10 s_i=10 的投票人按照 a i a_i 进行排序并求影响力的前缀和
  • s i = 00 s_i=00 的投票人干同样的事情
  • 下面设 n x n_x s i = x s_i=x 的投票人个数
  • 枚举 s i = 10 s_i=10 的投票人选出的个数 k k
  • 那么如果 n 11 + k < n 01 n_{11}+k<n_{01} (支持 Alice 的人太少)或者 n 11 + n 01 < k n_{11}+n_{01}<k (支持 Bob 的人太少)则这个 k k 不合法
  • 否则之多可以选择 min ( n 00 , n 11 + k n 01 , n 11 + n 01 k ) \min(n_{00},n_{11}+k-n_{01},n_{11}+n_{01}-k) s i = 00 s_i=00 的投票人
  • 上式 min \min 内第一个参数为 s i = 00 s_i=00 的人数,第二个参数表示支持 Alice 1人数减去不支持 Alice 的人数(换句话说,表示最多还能有多少个人不支持 Alice ),第三个参数表示最多还能有多少个人不支持 Bob 。
  • 显然在 s i = 00 s_i=00 的人中选出一些以及在 s i = 10 s_i=10 的人中选出一些,必须选择影响力最大的几个
  • 利用排序之后预处理处的前缀和更新答案
  • 复杂度 O ( n log n ) O(n\log n) (含排序)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}

template <class T>
inline T Min(const T &a, const T &b) {return a < b ? a : b;}

inline bool comp(const int &a, const int &b)
{
	return a > b;
}

const int N = 4e5 + 5;

int n, n00, n01, n10, n11, a00[N], a01[N], a10[N], a11[N], delta, tot, ans;

int main()
{
	int i, x, y;
	n = read();
	For (i, 1, n)
	{
		x = read(); y = read();
		if (!x) a00[++n00] = y;
		else if (x == 1) a01[++n01] = y;
		else if (x == 10) a10[++n10] = y;
		else a11[++n11] = y;
	}
	std::sort(a00 + 1, a00 + n00 + 1, comp);
	std::sort(a01 + 1, a01 + n01 + 1, comp);
	std::sort(a10 + 1, a10 + n10 + 1, comp);
	For (i, 1, n11) delta += a11[i], tot++;
	For (i, 2, n00) a00[i] += a00[i - 1];
	For (i, 2, n01) a01[i] += a01[i - 1];
	For (i, 2, n10) a10[i] += a10[i - 1];
	For (i, 0, n01)
	{
		if (tot + i < n10 || tot + n10 < i) continue;
		ans = Max(ans, a01[i] + a10[n10] +
			a00[Min(n00, Min(tot + i - n10, tot + n10 - i))]);
	}
	For (i, 0, n10)
	{
		if (tot + i < n01 || tot + n01 < i) continue;
		ans = Max(ans, a10[i] + a01[n01] +
			a00[Min(n00, Min(tot + i - n01, tot + n01 - i))]);
	}
	std::cout << ans + delta << std::endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/84592278