题解:P12466 『FCRT / 1 - 3』Wordle
我们不妨将
设答案序列为
所以询问的本质就是给一个序列
假设现在
什么样的
于是这容易贪心解决,首先尽量让
容易发现
这样每一次猜测都是最优的,正确性容易证明。
#include <iostream>
#include <vector>
#include <functional>
#include <numeric>
using namespace std;
int n;
string s;
char Right_shift (char c, int x) {
if (x >= 26) c = (c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c - 'A' + 'a'), x -= 26;
char goal = (c >= 'a' && c <= 'z' ? 'z' : 'Z');
int walk = min(x, goal - c);
c += walk, x -= walk;
if (c == goal && x) {
if (c == 'z') c = 'A' + x - 1;
else c = 'a' + x - 1;
}
return c;
}
int Ask (vector<int> a) {
auto it = s.begin();
for (int i = 0; i < 52; ++i) {
while (a[i]--) cout << Right_shift(*it, i), ++it;
}
cout << endl;
int ret;
cin >> ret;
return ret;
}
void Answer (int k) {
for (auto c : s) cout << Right_shift(c, k);
cout << endl;
int ret;
cin >> ret;
if (ret != n) {
cout << "Error ! " << endl;
exit(1);
}
}
void Solve () {
cin >> s, n = s.size();
vector<int> st(52);
iota(st.begin(), st.end(), 0);
while (true) {
// cout << "! " << st.size() << '\n';
int cnt = st.size(), L = 1, R = cnt;
vector<int> way;
while (L <= R) {
int mid = (L + R) >> 1;
vector<int> lis;
for (int v = 0; ; ++v) {
int ned = min(cnt - int(lis.size()), mid);
for (int i = 0; i < ned; ++i) lis.push_back(v);
if (lis.size() == cnt) break;
}
int sum = 0;
for (auto i : lis) sum += i;
if (sum <= n) {
lis.back() += n - sum;
way = lis;
R = mid - 1;
}
else {
L = mid + 1;
}
}
vector<int> mp(52);
for (int i = 0; i < cnt; ++i) mp[st[i]] = way[i];
int ret = Ask(mp);
if (ret == n) return;
vector<int> candi;
for (int i = 0; i < cnt; ++i) {
if (way[i] == ret) candi.push_back(st[i]);
}
if (candi.size() == 1) {
Answer(candi[0]);
return;
}
st = candi;
}
}
int main () {
int T;
cin >> T;
while (T--) Solve();
return 0;
}