题意:交互题。有一个长度为 n(n <= 1000) 的未知字符串S,通过最多 26 次 1 查询和 6000 次 2 查询,确定字符串。1 查询:输入 i ,返回字符Si 。 2 查询:输入 l,r ,返回字符串Sl 到 Sr 不同字符的数量。
思路:只有 26 次 1 查询,说明每个字符只能查一次,通过 n 次 2 查询可以确定每个字符是否是第一次出现,如果是第一次出现那么就用 1 查询确定是什么字符。否则就要通过前面的信息用 2 查询来确定是什么字符,用一个数组存储 26 个字符最后一次出现的位置,通过这26个位置和当前待确定字符的位置,可以确定当前字符和前面哪个一个字符相同,平均每个字符最多只有5次查询,一共26个位置,用二分可以满足。
代码:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, P = 1e9 + 7, mod = 998244353;
char ask1(int r){
printf("? 1 %d\n", r);
fflush(stdout);
char ch; cin >> ch;
return ch;
}
int ask2(int l, int r){
printf("? 2 %d %d\n", l, r);
fflush(stdout);
int x; cin >> x;
return x;
}
void solve(){
int n;
cin >> n;
vector<int>a(26);
string s(n + 1, ' ');
int cnt = 0;
for(int i = 1; i <= n; i++){
int x = ask2(1, i);
if(x > cnt){
cnt = x;
s[i] = ask1(i);
a[s[i] - 97] = i;
}else{
vector<int>b;
for(int j = 0; j < 26; j++) if(a[j]) b.pb(a[j]);
sort(b.begin(), b.end());
int l = 0, r = b.size() - 1;
while(l < r){
int mid = l + r >> 1;
if(cnt - mid - 1 != ask2(b[mid] + 1, i)) r = mid;
else l = mid + 1;
}
s[i] = s[b[l]];
a[s[i] - 97] = i;
}
}
cout << "!" << s << endl;
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
//cin >> t;
//while(t--){
solve();
//}
return 0;
}