給定長度 n、字符集大小 p(前 p 個小寫字母)、一個合法字符串(無長度≥2 的回文子串)。求字典序下一個合法字符串,不存在輸出 "NO"。
s[i] != s[i-1] 且 s[i] != s[i-2])is[i] 增加到 'a'+p-1 範圍內的最小合法字符(不等於左側 1、2 位)i+1 到末尾,每位填最小合法字符(不等於左側 1、2 位)#include <cstdio>
#include <cstring>
using namespace std;
char a[1234567];
int n, p;
// 嘗試在位置 now 增加字符,成功返回 true
bool judge(int now) {
for (int i = 1; ; ++i) {
if (a[now] + i > 'a' + p - 1) return false;
if (now > 0 && a[now] + i == a[now-1]) continue;
if (now > 1 && a[now] + i == a[now-2]) continue;
a[now] += i;
return true;
}
}
// 位置 now 填最小合法字符
void get_min(int now) {
for (int i = 0; ; ++i) {
if (now > 0 && 'a' + i == a[now-1]) continue;
if (now > 1 && 'a' + i == a[now-2]) continue;
a[now] = 'a' + i;
return;
}
}
int main() {
scanf("%d%d", &n, &p);
scanf("%s", a);
int ok = 0, pos = -1;
for (int i = n-1; i >= 0; --i) {
if (judge(i)) { ok = 1; pos = i; break; }
}
if (ok) {
for (int i = pos+1; i < n; ++i) get_min(i);
printf("%s\n", a);
} else {
printf("NO\n");
}
return 0;
}
此題屬於「字典序下一個合法序列」經典模板,關鍵在於合法性判斷的局部性(只依賴左側常數位置)。