CF - 794C. Naming Company - 贪心+排序+模拟+字符串处理

本文介绍了一个命名博弈游戏,其中两名玩家Oleg和Igor通过交替选择字母来决定公司的名称,目标分别是使名称字典序最小和最大。文章详细阐述了解决方案,包括策略制定和使用双端队列进行实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目描述:

C. Naming Company
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Oleg the client and Igor the analyst are good friends. However, sometimes they argue over little things. Recently, they started a new company, but they are having trouble finding a name for the company.

To settle this problem, they've decided to play a game. The company name will consist of n letters. Oleg and Igor each have a set of nletters (which might contain multiple copies of the same letter, the sets can be different). Initially, the company name is denoted by nquestion marks. Oleg and Igor takes turns to play the game, Oleg moves first. In each turn, a player can choose one of the letters c in his set and replace any of the question marks with c. Then, a copy of the letter c is removed from his set. The game ends when all the question marks has been replaced by some letter.

For example, suppose Oleg has the set of letters {i, o, i} and Igor has the set of letters {i, m, o}. One possible game is as follows :

Initially, the company name is ???.

Oleg replaces the second question mark with 'i'. The company name becomes ?i?. The set of letters Oleg have now is {i, o}.

Igor replaces the third question mark with 'o'. The company name becomes ?io. The set of letters Igor have now is {i, m}.

Finally, Oleg replaces the first question mark with 'o'. The company name becomes oio. The set of letters Oleg have now is {i}.

In the end, the company name is oio.

Oleg wants the company name to be as lexicographically small as possible while Igor wants the company name to be as lexicographically large as possible. What will be the company name if Oleg and Igor always play optimally?

A string s = s1s2...sm is called lexicographically smaller than a string t = t1t2...tm (where s ≠ t) if si < ti where i is the smallest index such that si ≠ ti. (so sj = tj for all j < i)

Input

The first line of input contains a string s of length n (1 ≤ n ≤ 3·105). All characters of the string are lowercase English letters. This string denotes the set of letters Oleg has initially.

The second line of input contains a string t of length n. All characters of the string are lowercase English letters. This string denotes the set of letters Igor has initially.

Output

The output should contain a string of n lowercase English letters, denoting the company name if Oleg and Igor plays optimally.

Examples
input
tinkoff
zscoder
output
fzfsirk
input
xxxxxx
xxxxxx
output
xxxxxx
input
ioi
imo
output
ioi
Note

One way to play optimally in the first sample is as follows :

  • Initially, the company name is ???????.
  • Oleg replaces the first question mark with 'f'. The company name becomes f??????.
  • Igor replaces the second question mark with 'z'. The company name becomes fz?????.
  • Oleg replaces the third question mark with 'f'. The company name becomes fzf????.
  • Igor replaces the fourth question mark with 's'. The company name becomes fzfs???.
  • Oleg replaces the fifth question mark with 'i'. The company name becomes fzfsi??.
  • Igor replaces the sixth question mark with 'r'. The company name becomes fzfsir?.
  • Oleg replaces the seventh question mark with 'k'. The company name becomes fzfsirk.

For the second sample, no matter how they play, the company name will always be xxxxxx.


2.题意概述:

O同学和P同学都想为公司取名字,假定公司名字长度为len,初始为全为“?????...??”,而O同学和P同学都有len个字符,并且他们互相知道对方有什么字符,现在从O同学开始轮流选一个字符替换任意的?,但是O同学希望公司最后的名字的字典序尽可能的小,而P同学却希望字典序尽可能地大,问你最终情况下公司的名称。

3.解题思路:

考虑贪心,容易观察如果len是奇数,则先手方一定出 下取整[len/2]+1个字符,而后手方出 下取整[len/2] 个字符,假设O同学出cnt1个,P同学出从cnt2个字符,先预处理出O同学和P同学将要出的字符(容易证明O同学的为前cnt1小的, P同学肯定出前cnt2大的),接下来就是看每次的选择策略了。因为位置可以是任意的,考虑:

如果是O同学的回合:

①如果O同学目前最小的字符大于等于P同学最大的字符,那么O同学肯定希望P同学这个字符放在O同学这个字符前面(这样字典序才尽可能地小),所以O同学此时的最优策略是出他现有集合里面最大的字符,并把它尽可能地放在后侧。

②如果O同学目前最小的字符小于P同学最大的字符,无疑O同学肯定赶紧把这个字符给尽可能放在前侧。

如果是P同学回合:

①如果O同学目前最小的字符大于等于P同学最大的字符,那么P同学肯定希望O同学这个字符放在P同学这个字符前面(这样字典序才尽可能地大),所以P同学此时的最优策略是出他现有集合里面最小的字符,并把它尽可能地放在后侧。

②如果P同学目前最大的字符大于O同学最小的字符,无疑P同学肯定赶紧把这个字符给尽可能放在前侧。

那么怎么动态维护两个同学现在的字符呢,考虑用双端队列,再用vector维护往前放的字符,stack(或者双端队列)维护往后放的字符,最后整合一下就行了。

4.AC代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 300100
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 1111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
char a[maxn], b[maxn];
vector<char> ans;
deque<char> q, A, B;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	long _begin_time = clock();
#endif
	while (~scanf("%s%s", a, b))
	{
		int len = strlen(a);
		sort(a, a + len);
		sort(b, b + len, greater<int>());
		ans.clear();
		q.clear();
		A.clear();
		B.clear();
		int cnt1 = len >> 1;
		int cnt2 = cnt1;
		if (len & 1)
			cnt1++;
		for (int i = 0; i < cnt1; i++)
			A.push_back(a[i]);
		for (int i = 0; i < cnt2; i++)
			B.push_back(b[i]);
		for (int i = 0; i < len; i++)
		{
			if (i & 1)
			{
				if (!A.empty() && B.front() <= A.front())
				{
					q.push_front(B.back());
					B.pop_back();
				}
				else
				{
					ans.push_back(B.front());
					B.pop_front();
				}
			}
			else
			{
				if (!B.empty() && A.front() >= B.front())
				{
					q.push_front(A.back());
					A.pop_back();
				}
				else
				{
					ans.push_back(A.front());
					A.pop_front();
				}
			}
		}
		while (!q.empty())
		{
			ans.push_back(q.front());
			q.pop_front();
		}
		for (int i = 0; i < len; i++)
			printf("%c", ans[i]);
		puts("");
	}
#ifndef ONLINE_JUDGE
	long _end_time = clock();
	printf("time = %ld ms.", _end_time - _begin_time);
#endif
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值