CF 1697 D. Guess The String 思维 + 二分 1900

12 篇文章 0 订阅

题意:交互题。有一个长度为 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值