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;
}
posted @ 2022-06-21 19:45  qingyanng  阅读(90)  评论(0编辑  收藏  举报