CF1697D. Guess The String (交互题)
https://codeforces.com/contest/1697/problem/D
题意:
有一个长度为n的有小写字母组成的字符串,
Ⅰ操作:查询i位置上的字母 (不超过26次)
Ⅱ操作:查询 l到r字母种类数 (不超过6000次)
思路:
- Ⅰ操作只能那个进行26次,可以想到从1到n查询前缀,si的种类数和si-1不同就说明i位置上是之前没有出现过的字母。
- 相同的话,考虑用Ⅱ操作判出i是哪个字母:保留每个字母最后一次出现的位置,根据种类数二分出和i相同的字母,Ⅱ操作最多用1000log26次
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, char>
//#define int long long
const int N = 2e5 + 5;
const int M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI = acos(-1.0);
void solve() {
int n; cin >> n;
vector<PII> ve; string ans;
cout << "? 1 " << 1 << endl;
char x; cin >> x;
ve.push_back({1, x}); ans += x;
for ( int i = 2; i <= n; ++ i ) {
cout << "? 2 " << 1 << " " << i << endl;
int ty; cin >> ty;
if( ty > ve.size() ) {
cout << "? 1 " << i << endl;
char x; cin >> x;
ve.push_back({i, x}); ans += x;
} else {
sort(ve.begin(), ve.end()); int sz = ve.size();
int l = 0, r = ve.size() - 1;
while( l < r ) {
int mid = l + r + 1 >> 1;
cout << "? 2 " << ve[mid].first << " " << i << endl;
int ty; cin >> ty;
if( ty == sz - (mid + 1) + 1 ) l = mid;
else r= mid - 1;
}
ve[l].first = i; ans += ve[l].second;
}
}
cout<<"! "<<ans<<endl;
}
int main () {
IOS
int t = 1;// cin >> t;
while ( t -- ) solve();
return 0;
}