思路

一道较水的模拟题。

首先,我们输入 kk 和字符串后,设置一个变量 whwh 代表不确定的问号对的数量,设置一个 bool 类型的数组 visivis_i 标记每个字母有没有出现过,然后用一个循环从字符串的两端向中间搜起,(代码里有)然后,如果搜到的两个字符不相同且不是 ?,直接输出 IMPOSSIBLE。如果两个字符一个是 ?,一个是字母,就把 ? 这个字符设置成字母,顺便用 vis[i] = 1 标记这个字母出现过。如果两个字符都是相同的字母,也要标记哦!如果两个字符都是 ?,则 wh ++,统计问号对出现的次数。

这样先把字符串能填的都填上,再统计一下有多少个字母没有出现过。

int xy = 0;
for (int i = 0;i < k;i ++) xy += !vis[i];

对于第 00 到第 kk 个小写字母,每有一个没出现过,xyxy 就加 11

我们又想到一种情况,如果可以用来填字母的问号对比没出现过的字母数还少,那肯定做不到让所有的字母起码出现一次,所以如果出现这种情况,也可以直接输出 IMPOSSIBLE 了!

按照刚刚的定义,还有 whwh 个不确定的问号对,和 xyxy 个没出现的字母,则有 whxywh-xy 个空闲的问号对。

根据贪心思想,我们要把空闲的问号对都填上 a,再根据字典序的排序方法,我们应该在问号对上面优先填上 a,再填上需要的字母。假如 kk33,而字符串为 a??????a,则应输出 aabccbaa。这就可以保证 abc 各出现至少一次而且字典序最小。

那要在什么情况下再填需要的字母呢?当然要在没有空闲问号对的情况下填了!

这样,问题就迎刃而解了!

代码

#include <iostream>
#include <string>

using namespace std;

string s;
int n, wh, xy;
char yt;
bool vis[26];
int main(){
	cin >> n >> s;
	for (int l = 0, r = s.size() - 1;!(r < l);r --, l ++){ // 定义左点和右点并向中间移动
		if (s[l] != '?' && s[r] != '?' && s[l] != s[r]){ // 都是字母且不相等
			cout << "IMPOSSIBLE";
			return 0;
		}
		if (s[l] == s[r]){ // 相等
			if (s[l] == '?') wh ++; // 都是问号则统计问号对
			else vis[s[l] - 'a'] = 1; // 都是字母则统计字母
		}
		else { // 不相等
			if (s[l] == '?') s[l] = s[r]; // 左问号右字母
			else s[r] = s[l]; // 相反
			vis[s[l] - 'a'] = 1; // 统计字母
		}
	}
	for (int i = 0;i < n;i ++) xy += !vis[i]; // 统计未出现的字母
	if (wh < xy){ // 问号对不够
		cout << "IMPOSSIBLE";
		return 0;
	}
	for (int l = 0, r = s.size() - 1;!(r < l);r --, l ++){
		yt = 'a'; // 先设置为 'a'
		if (s[l] == '?'){ // 发现问号对
			if (wh <= xy){ // 不能填 'a' 了
				int i;
				for (i = 0;i < n && vis[i];i ++) yt ++; // 找到第一个没出现过的字母
				vis[i] = 1; // 标记为出现过
			}
			else wh --; // 可以填 'a',空闲的问号对 - 1
			s[l] = s[r] = yt; // 把两个问号设置成字母
		}
	}
	cout << s; // 输出字符串
}