ABC355E Guess the Sum 题解
ABC355E Guess the Sum
题目大意#
给定一个长度为 的序列 ,每次可以询问一个长度为 的区间 ,满足 是 的倍数,标准输入会返回 的区间和 的结果,要求以最少的次数计算出给定区间 的区间和。
Solve#
令 为原序列的前缀和数组,询问区间 的区间和相当于询问 。
考虑在前缀和上建图,如果可以询问区间 ,那么就在 和 间连一条无向边。建边后从 跑单源最短路即可,可以用 BFS 跑,因为边权都是 。
至于输出询问,我们可以对于每个点 ,用 记录它是从哪个点转移过来的,最后从 跑一遍 DFS 即可。
注意,原序列的下标从 开始,所以访问 时会出问题,应将原序列下标整体加一。
Code#
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
short f=1;
int x=0;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,a,b,ans,res,fa[1<<19];
vector<int>e[1<<19];
bool vis[1<<19];
void bfs()
{
queue<int>q;
q.push(a);vis[a]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(auto i:e[u])
if(!vis[i])
{
fa[i]=u;vis[i]=1;
if(i==-~b) return;
q.push(i);
}
}
}
void dfs(int u)
{
int len=log2(abs(fa[u]-u));
if(fa[u]>u)//若转移点在当前点右侧,说明是走回头路,应减去这一段区间和。
printf("? %lld %lld\n",len,u/(1<<len)),
fflush(stdout)/*清空缓冲区*/,ans-=(res=read());
else//否则应加上区间和
printf("? %lld %lld\n",len,(fa[u])/(1<<len)),
fflush(stdout),ans+=(res=read());
if(res==-1) exit(0);//依题意,若询问不合法或询问次数多于最小次数标准输出会返回-1,此时退出。
if(fa[u]!=a) dfs(fa[u]);//若是从起点a-1转移过来,则说明已询问完,此时不再继续询问。
}
signed main()
{
n=read();a=read();b=read();
for(int len=(1<<n);len;len>>=1)
for(int i=1;i+len-1<=(1<<n);i=-~i)
if((i-1)%len==0)//建图
e[i-1].push_back(i+len-1),e[i+len-1].push_back(i-1);
bfs();dfs(-~b);
printf("! %lld",(ans%100+100)%100);
fflush(stdout);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】