Croc Champ 2013 - Round 2 A. Weird Game【博弈 贪心】
题目链接:A. Weird Game*1500
蒟蒻只是在这里记录一下思路,大佬有什么更好的方法恳请指教。
题目大意:两个人各拥有一个01串a,b,长度为2n,分先后手,每一回合挑选一个最佳字符来使自己的得到1更多,挑选过字符的位置不允许再挑选。问最终谁挑选得到的1更多。
解题思路:
我们知道最终每个人手上有n个字符。观察,会有4种情况:
<1>同一位置,a,b串都有1;
<2>同一位置,a串有1,b串是0;
<3>同一位置,b串有1,a串是0;
<4>同一位置,a,b串都是0;
则轮到一个人的回合,他一定会先拿取<1>情况位置的字符,因为这样产生的贡献最大,可以让自己1增多,也尽可能的减少对方可选择的1的个数;
若不存在<1>的情况,他会尽可能的使自己的1增多,或使对方可选择的1减少,进而选择<2>或<3>的位置。
如果连<2><3>都选完了,剩下的<4>不产生对答案的贡献。
那么,我们该如何编写我们的代码呢?
我们知道,<1>会使贡献+1,若个数为偶数,那么两个人选择<1>的数量会相同,相当于贡献被抵消了;若为奇数,则作为先手的a会多得一个贡献,会+1。这里,我们解决了<1>对双方产生贡献的多少。
那关于<2><3>对答案的贡献如何求呢?
两个人选择<2>和<3>产生的贡献是等同的,所以最终贡献的差异体现在两个的数量之差上。假设 <2> > <3> ,则不妨设d=<2> - <3>,那么一个回合一个人选,我们要判断这时谁是先手,因为选<1>造成的。如果<1>个数是偶数,则a仍为先手,若d为偶数,则a会+d/2的贡献;若d为奇数,则a会+(d+1)/2的贡献==>都可写为(d+1)/2。其他情况类推。则最后比较两者的大小,输出即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 9;
// game greedy
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
// input
int n;cin >> n;
string a,b;cin >> a >> b;
// 初始化
int aa,bb,cc,ca,cb,ok;aa = bb = cc = ca = cb = ok = 0;
`
for(int i = 0;i < 2*n;++ i)
{
if(a[i] == '1' && b[i] == '1') cc ++; // <1>的数量
if(a[i] == '1' && b[i] == '0') aa ++; // <2>的数量
if(a[i] == '0' && b[i] == '1') bb ++; // <3>的数量
}
// 如果cc是奇数,则先手的a会比b多产生1个贡献,而这之后,会有b来进行选择,所以后面进行分类讨论
if(cc&1) {ok = 1;ca += 1;}
// cc为偶数
if(ok == 0)
{
if(aa > bb) {ca += (aa - bb + 1) / 2;}
if(aa < bb) {cb += (bb - aa) / 2;}
}
// cc为奇数
else
{
if(aa > bb) {ca += (aa - bb) / 2;}
if(aa < bb) {cb += (bb - aa + 1) / 2;}
}
// output
if(ca > cb) cout << "First\n";
else if(ca < cb) cout << "Second\n";
else cout << "Draw\n";
return 0;
}