您的位置:首页 > 其它

bzoj4391: [Usaco2015 dec]High Card Low Card

2018-01-02 16:04 357 查看
题面在这里

题意:

有2*n张牌,编号为1~2n,两个人各拿n张。现在A知道B n轮出的牌。

规定前1~i轮编号大的人胜,后i+1~n轮编号小的人胜。

问选择恰当的i,A最多能胜几轮。

做法:

记f[i]表示前i轮中A最多能胜的轮数,g[i]表示后i~n轮中A最多能胜的轮数

答案就是max(f[i]+g[i+1])(0<=i<=n)

现在来考虑如何计算f[]g[]。

一个比较直接的贪心想法就是,计算f的时候,每次取刚好大于它的数,计算g的时候,每次取刚好小于它的数

但是这样可能会有f和g中取的数重复。

但是没关系。我们假设a被取了两次,那么肯定有一个没被取过的b,如果b<a,就在计算g的时候将a替换成b;反之也一样。

所以答案肯定是正确的。

代码:

/*************************************************************
Problem: bzoj 4391 [Usaco2015 dec]High Card Low Card
User: fengyuan
Language: C++
Result: Accepted
Time: 528 ms
Memory: 3032 kb
Submit_Time: 2018-01-02 15:45:46
*************************************************************/

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

const int N = 50010;
const int INF = 1e9;
int n;
int a
, f
, g
;
bool vis[N<<1];

int main()
{
//freopen("testdata2.in", "r", stdin);
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), vis[a[i]] = 1;
set<int> s;
for(int i = 1; i <= n<<1; i ++) if(!vis[i]) s.insert(i);
f[0] = 0;
for(int i = 1; i <= n; i ++) {
f[i] = f[i-1];
set<int>::iterator it = s.upper_bound(a[i]);
if(it != s.end()) f[i] ++, s.erase(it);
}
s.clear();
for(int i = 1; i <= n<<1; i ++) if(!vis[i]) s.insert(i);
g[n+1] = 0;
for(int i = n; i >= 1; i --) {
g[i] = g[i+1];
set<int>::iterator it = s.lower_bound(a[i]);
if(it == s.begin()) continue; it --;
g[i] ++, s.erase(it);
} int ans = 0;
for(int i = 0; i <= n; i ++) ans = max(ans, f[i] + g[i+1]);
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: