【思维题】【贪心】【模拟】【CodeForces】794 C Naming Company

34 篇文章 0 订阅
11 篇文章 0 订阅

【题目】http://codeforces.com/problemset/problem/794/C

【题意】

两个人A和B在玩一个填字母游戏。现在A和B都有一个包含 n 个小写字母的多重集合(可以有重复字符)。

初始有一个长度为n的空字符串s,两人轮流操作,A先手。一次操作可以将自己集合中的一个字母拿出来,放到字符串s的某个空位置,然后把这个字母从自己集合中删除(如果有多个只删一个)。直到字符串s被填满游戏结束。

A的目标是让字符串s字典序最小,而B的目标是让字符串s字典序最大。假设两人都无比聪明,问游戏结束后字符串s是怎么样的。

Input

第一行包含一个字符串 s ,长度为 n (1 ≤ n ≤ 3·105). 每个字符都是小写英文字母,表示A拥有的多重集合。

第二行包含一个字符串 t 长度为 n。每个字符都是小写英文字母,表示B拥有的多重集合。

Output

输出为一个长度为 n 的小写英文字母串,表示所有操作完之后的字符串。

 【思路】

我们可以知道,A只有两种策略:1:将自己最小的字符放到答案的最前面;2:或者将自己最大的字符放在最后面。

当A中的字符全部>=B中的字符,i.e.自己最小的字符>=B最大的字符时,就应该把自己最大的字符尽可能往后放,也就是选择第二种方式。这样就会逼迫B把字典序小的字符放在前面。

当A里有比B中小的字符,即自己最小的字符<B最大的字符时,就应该让这个最小的字符占据尽可能靠前的位置,也就是选择第一种方式。

同理,B也只有两种策略:1:将最大的字符放在最前面;2:将最小的字符放在最后。

当B中的字符全部<=A中的字符,即B的最大的字符<=A最小的字符时,就应该把最小的字符尽可能往后放,让A不得不把字典序大的字符放在前面。

当B中存在比A中任意字符大,即B的最大字符>A最小的字符时,就应该尽可能让这个字符靠前。

另外注意:当是奇数的时候,A会多操作一次,所以A的备选串长度是n/2+1;否则AB都是n/2。

                  当是奇数时,A多操作的那一次B的备选串已经为空,无需比较直接输出即可。

【代码】

#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;

const int M=3e5+5;
const int inf=1e9+5;

char x[M];
deque<char>q1;//双向队列储存已经排好序的备选串
deque<char>q2;

stack<char>s;//用栈储存尾巴

bool cmp(char a,char b)
{
    return a>b;
}

int main()
{
    scanf("%s",x);
    int len=strlen(x);
    sort(x,x+len);//A取小字符
    int t;
    if(len%2==1)
        t=len/2+1;
    else
        t=len/2;
    for(int i=0; i<t; i++)//len为奇数时,A会1个字符
    {
        q1.push_back(x[i]);
    }
    scanf("%s",x);
    sort(x,x+len,cmp);//B取大字符
    for(int i=0; i<len/2; i++)
    {
        q2.push_back(x[i]);
    }

    for(int i=0; i<len; i++)
    {
        if(i%2==0)//当A操作时
        {
            if(q2.empty())//如果是len奇数的最后一次操作
            {
                cout<<q1.front();//直接输出
                q1.pop_front();
            }
            else if(q1.front()>=q2.front())
                //如果A中字符全部>=B中字符
            {
                s.push(q1.back());//把最大的字符放到后面
                q1.pop_back();
            }
            else
            //如果存在字符<B中任意字符
            {
                cout<<q1.front();//把最小的字符放到前面
                q1.pop_front();
            }

        }
        else//当B操作时
        {
            if(q2.front()<=q1.front())
                //如果B中字符全都<=A中字符
            {
                s.push(q2.back());//把最小的字符放后面
                q2.pop_back();
            }
            else//如果存在字符>A中任意字符
            {
                cout<<q2.front();//把最大的字符放前面
                q2.pop_front();
            }

        }
    }
    while(!s.empty())//输出尾巴
    {
        cout<<s.top();
        s.pop();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值