Address
洛谷 RemoteJudge
Codeforces 1070F
Meaning
- Alice 和 Bob 参加选举
- 有 个投票人,第 个人有两个属性 和
- 对于第 个人, 是一个长度为 的 串
- 表示第 个人不支持 Alice 和 Bob
- 表示第 个人不支持 Alice 但支持 Bob
- 表示第 个人支持 Alice 但不支持 Bob
- 表示第 个人支持 Alice 和 Bob
- 第 个人的影响力为
- 现在要从中选出一些人,满足下面 个条件
- (1)选出的人中,支持 Alice 的人数的 倍大于或等于选出的人数
- (2)选出的人中,支持 Bob 的人数的 倍大于或等于选出的人数
- 求选出的人的影响力之和的最大值
Solution
- 考虑把所有投票人按照 分开,显然在最优方案中 的投票人必须被选出
- 然后重点对 、 、 进行分析
- 一个结论:在最优方案中,所有 的投票人全部被选出,或者所有 的投票人全部被选出
- 证明:如果有一种合法方案,有 个 的投票人没被选出,有 个 的投票人没被选出
- 那么再选 个 的投票人和 个 的投票人则显然还是合法
- 下面对 的投票人全部被选出的情况进行讨论( 的投票人全部被选出的情况同理)
- 先把 的投票人按照 进行排序并求影响力的前缀和
- 的投票人干同样的事情
- 下面设 为 的投票人个数
- 枚举 的投票人选出的个数
- 那么如果 (支持 Alice 的人太少)或者 (支持 Bob 的人太少)则这个 不合法
- 否则之多可以选择 个 的投票人
- 上式 内第一个参数为 的人数,第二个参数表示支持 Alice 1人数减去不支持 Alice 的人数(换句话说,表示最多还能有多少个人不支持 Alice ),第三个参数表示最多还能有多少个人不支持 Bob 。
- 显然在 的人中选出一些以及在 的人中选出一些,必须选择影响力最大的几个
- 利用排序之后预处理处的前缀和更新答案
- 复杂度 (含排序)
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;
}