CodeChef Starters 26 Division 3 (Rated)----STNGAME(中文题解)

描述:

Contest Page | CodeChef

上面是原题目的地址,简要概括一下意思:Alice和Bob在玩一个填字符串的游戏,一开始Alice有n个字符,Bob也有n个字符。他们需要用这些字符填成一个长度为2n的字符串。Alice先手,并且她想要让字符串尽可能按字典序上升,Bob后手,他想让字符串尽可能地按字典序下降。

分析:

情景分析①

        Alice想要让这个字符串是按字典序升序排列的,所以她的游戏策略是:要让现在字符串当中最小下标的空位,被现在能够用于填充的(也就是Alice和Bob手上拿着的那些没有填的字符)最小字符填充;同样的,现在在字符串当中下标最大的空位,被现在能够用于填充的最大字符串填充。同样的道理,Bob的填充策略应该是与Alice相反的。

情景分析②

我们现在考虑这个情景:

        Alice手中的字符比Bob手中的字符都要大(lexicographically larger),比如Alice手上有:T/Y/U/I/O,而Bob手上有:A/C/D/F/G。现在,Alice显然不能用自己手上最小的字符去填充字符串当中下标最小的空白位置,她应该用自己手上最大的字符去填充字符串当中下标最大的空白位置。

        同样的,对于Bob而言,现在的他倘若要用自己最大的字符去填充字符串当中最小下标的空白位置,这显然不是一个最优的策略,他应该用自己最小的字符去尽量填充字符串当中下标最大的空白位置。

问题分析:

Alice的最优策略:

·将最小的字符放在字符串的最小下标的空位处

·将最大的字符放在字符串的最大下标的空位处

Bob的最优策略:

·将最大的字符放在字符串的最小下标的空位处

·将最小的字符放在字符串的最大下标的空位处

        假设现在是Alice的回合,现在她从她的字符中取出了一个最小的字符。如果这个字符比Bob最大的字符还要大,那就说明Alice的全部字符都要比Bob的要大,进而我们可以推出Alice有现在场上最大的字符,按照最优策略,Alice将把她最大的字符放在字符串的最大下标空位处。    

        另一方面,如果Alice最小的字符没有Bob最大的字符大,那么现在倘若Alice不把最小的字符放在最小下标空位处,Bob就会在上面放一个大的字符,这显然会比Alice现在的结果更坏,所以这个时候,Alice应该将自己最小的字符放在最小下标空位处。

        Bob的回合也是相似的。Bob在自己能够选择的所有字符中选出最大的那一个,假如这个字符比Alice最小的字符还要小,那就说明Bob的所有字符都比Alice的最小的字符要小,并且他还拥有所有字符中的最小值,这个时候如果Bob还打算将自己最大的字符放置于最小下标空位处那就正中Alice下怀了。所以在这种情况下,Bob要将自己最小的字符放到最大下标空位处。

        就像我们分析Alice时一样,如果这个时候Bob的最大字符比Alice的最小字符要大。如果Bob不把他最大的字符放在最小下标空位处,Alice最起码可以把她最小的字符放在那个位置,那这样Bob就不再是最优解了。    

        我们应该注意到的是,上面说的最优解都是当前的最优解,所以这是一个两个玩家都在用贪心策略对抗的游戏。好了,细心如你,你可能已经发现了,我们好像并没有讨论当Alice的最小字符等于Bob的最大字符的情况。我们刚才考虑了,轮到Alice的时候,如果Alice最小的字符比Bob最大的字符还要大,那么Bob只需要拿一个最小的字符填到最大下标空位处就可以阻止Alice获得最优字符,为了阻止Bob,Alice只好将自己最小的字符放到最后面,其实二者相同的时候也是一样的道理。

代码实现:

#include<bits/stdc++.h>
using namespace std;
int main() {
    
    int t;
    cin >> t;
    while(t--){
        int n; cin >> n;
        vector<char> a(n),B(n);
        deque<char> an,bn;
        for(auto &i : a) cin >> i;
        for(auto &i : B) cin >> i;

        sort(a.begin(), a.end());//从小到大
        sort(B.rbegin(), B.rend());//从大到小

        for(auto o:a) an.push_back(o);
        for(auto o:B) bn.push_back(o);

        vector<char> ans(2*n);
        int f=0, b=2*n-1;

        for(int i=0;i<2*n;i++){
            if((i%2)==0){
                if(bn.size() && an.front() >= bn.front()){
                    ans[b--] = an.back();
                    an.pop_back();
                }else{
                    ans[f++] = an.front();
                    an.pop_front();
                }
            }else{
                if(an.size() && an.front() < bn.front()){
                    ans[f++] = bn.front();
                    bn.pop_front();
                }else{
                    ans[b--] = bn.back();
                    bn.pop_back();
                }
            }
        }

        for(auto i:ans) cout<<i;
        printf("\n");
    }
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值