人,只有自己站起来,这个世界才能属于他。|

园龄:粉丝:关注:

题解:[ABC355E] Guess the Sum

abc355_e 解题报告

前言

好玩的交互题!

思路分析

首先注意到题目要求最小化询问次数,感觉瓶颈不在于得出答案,而是如何合理的询问。

发现可以转化为图论问题。

具体地,我们对于每一组合法的询问 [L,R),从 LR 连一条边权为 1 的无向边,表示用 1 的代价可以拓展已知区间。

然后跑 LR 的最短路,答案就是最少询问次数,询问就是最短路上的边。

注意从 LR 的边是增加 ans,从 RL 的边是减少 ans

有些细节,看代码吧。

复杂度不想算了。O()

代码实现


#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,l,r,pw[21];
int head[2000005],nxt[8000005],target[8000005],tot;
void add(int x,int y){
	tot++;
	nxt[tot]=head[x];
	head[x]=tot;
	target[tot]=y;
} 
void init(){
	pw[0]=1;
	for(int i=1;i<=n;i++){
		pw[i]=pw[i-1]*2;
	}
	for(int i=0;i<=n;i++){
		for(int j=0;j<=pw[n];j++){
			//if(!pw[i]*j) cout<<pw[i]*j<<' '<<pw[i]*(j+1)<<endl;
			if(pw[i]*(j+1)<=pw[n]) add(pw[i]*j,pw[i]*(j+1));
			if(j && pw[i]*j<=pw[n]) add(pw[i]*j,pw[i]*(j-1));
		} 
	}
}
int dis[2000005],pre[2000005];
queue<int> q;
void bfs(){
	memset(dis,0x3f,sizeof(dis));
	dis[l]=0;
	q.push(l);
	while(q.size()){
		int x=q.front();
		q.pop();
		for(int i=head[x];i;i=nxt[i]){
			int y=target[i];
			if(dis[y]>dis[x]+1){
				dis[y]=dis[x]+1;
				pre[y]=x;
				q.push(y);
			}
		} 
	} 
}
struct node{
	int l,r;
};
vector<node> ans;
int cnt;
void dfs(int x){
	cnt++;
	if(x==l) return;
	ans.push_back((node){pre[x],x});
	dfs(pre[x]);
}
int sum=0,tp;
void out(int l,int r){
	if(l>r) swap(l,r);
	int i=__lg(r-l);
	int j=l/pw[i];
	cout<<"? "<<i<<' '<<j<<endl;
	//cout<<pw[i]*j<<' '<<pw[i]*(j+1)-1<<endl;
}
void solve(){
	for(int i=0;i<ans.size();i++){
		out(ans[i].l,ans[i].r);
		cin>>tp;
		if(ans[i].l<ans[i].r) sum=(sum+tp)%100;
		else sum=(sum-tp+100)%100; 
	}
	cout<<"! "<<sum<<endl;
}
signed main(){
	cin>>n>>l>>r;
	r++;
	init();
	bfs();
	dfs(r);
	solve();
}

后记

喜欢好玩的题。

本文作者:Kenma

本文链接:https://www.cnblogs.com/Kenma/p/18689791

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起