用字典树做
预处理 每个数字前面都是0(2变为000002)
关键要处理好找到的字符串和原字符串是否一样
如果一样的话 只能继续找个不一样的 所以用fa数组记录每个节点的父亲 方便回去重新找
代码
#include<iostream>
#include<string>
using namespace std;
const int N = 1e5 + 5;
int n;
string ss[N];
int id;
int cnt[N];//以i号节点结尾的数出现的次数
int trie[N][10];
int fa[N];
string s2;
void create(string s) {
int now = 0;
for (auto it : s) {
if (trie[now][it - '0'] == 0) {
trie[now][it - '0'] = ++id;
fa[id] = now;
}
now = trie[now][it - '0'];
}
cnt[now]++;
}
inline string find(string s) {
string res;
for (auto it : s)
res += '9' - it + '0';
return res;
}
string solve(string s) {
//返回最接近s的字符串
string res;
int now = 0;
for (int i = 0; i < 6; i++) {
//对于每位数字
int num = s[i] - '0';
while (trie[now][num] == 0) {
num = num ? num - 1 : 9;
}
res += '0' + num;
now = trie[now][num];
//cout << res << endl;
}
if (res == s2 && cnt[now] == 1) {
//字符串重复 回溯找串
int pos = 5;
while (true) {
int c = res.back() - '0';
int num = c ? c - 1 : 9;
res.pop_back();
now = fa[now];
while (num != c && trie[now][num] == 0) {
num = num ? num - 1 : 9;
}
if (num == c) {
pos--;
continue;
}
else {
res += '0' + num;
pos++;
now = trie[now][num];
break;
}
}
for (int i = pos; i < 6; i++) {
int num = s[pos] - '0';
while (trie[now][num] == 0)
num = num ? num - 1 : 9;
res += num + '0';
now = trie[now][num];
}
}
return res;
}
int main(void) {
cin >> n;
for (int i = 1; i <= n; i++) {
string s1;
cin >> s1;
int len = s1.size();
while (6 - len > 0) {
ss[i] += '0';
len++;
}
ss[i] += s1;
create(ss[i]);
}
int black = 0;
for (int i = 1; i <= n; i++) {
s2 = ss[i];
if (black)cout << " ";
else black++;
//找出ss[i]的最优解
string s = find(ss[i]);
string ans = solve(s);
string res;
for (int j = 0; j < 6; j++) {
res += (ss[i][j] - '0' + ans[j] - '0') % 10 + '0';
}
int pos = 0;
while (pos < 6 && res[pos] == '0')pos++;
if (pos == 7)cout << 0;
else cout << res.substr(pos);
}
return 0;
}