1. 程式人生 > >【思維題】【貪心】【模擬】【CodeForces】794 C Naming Company

【思維題】【貪心】【模擬】【CodeForces】794 C Naming Company

【題意】

兩個人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;
}