题意:给定一个长度为 n(n<105) 且仅由小写英文字母构成的字符串,求它的一个重排列,使得构成的字符串于之前字符串上每个对应位置上的字母都不一样。
思路:贪心,找到出现次数最多的字母,然后把它优先填到出现次数少的字母那里,然后其余字符串整个右移「出现最多的字母出现次数」位,得到的就是结果。
(开始我想的是按字母次数多少倒过来摆放,例如aabbccc变成cccbbaa,但是这样不行,于是就猜想如何在这个倒过来摆放的序列上优化修改。殊不知一开始这样的想法就错了。以后不能总在自己的思路上往下走,应当质疑原先思路是否正确。)
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define ull unsigned long long
using namespace std;
const int maxn = 100010;
int cnt[30], pos[maxn];
char s[maxn], ans[maxn];
bool cmp(int a, int b) {
int x = s[a] - 'a', y = s[b] - 'a';
if(cnt[x] == cnt[y])
return x < y;
return cnt[x] < cnt[y];
}
int main() {
//freopen("in.txt","r",stdin);
while(scanf("%s",s) == 1) {
memset(cnt, 0, sizeof(cnt));
int len = strlen(s);
for(int i=0; i<len; i++) {
cnt[s[i]-'a'] ++;
pos[i] = i;
}
int alpha = 0, mx = -1;
for(int i=0; i<26; i++) if(cnt[i] >= mx) {
mx = cnt[i];
alpha = i;
}
sort(pos, pos+len, cmp);
for(int i=0; i<len; i++) {
if(i < mx)
ans[pos[i]] = alpha + 'a';
else
ans[pos[i]] = s[pos[i-mx]];
}
bool f = 1;
for(int i=0; i<len; i++)
if(s[i] == ans[i]) f = 0;
if(f) {
for(int i=0; i<len; i++)
putchar(ans[i]);
puts("");
}
else
puts("impossible");
}
return 0;
}