https://atcoder.jp/contests/abc188/tasks/abc188_f
md第二次被ABCF卡住,菜得一比
我们观察得到一个比较显然的结论,那就是如果y是偶数,那么x>=y/2时,要么直接到y,要么先到y/2再到y,因为如果你走到y/2+1再乘2,最后要减去2,所以在小的时候就要尽量满足后来差得越少,不然一次乘2相差就放大一倍
如果y是奇数,x>y/2,则要么到y/2+1再到y,要么直接到y
特别地,x>=y时,只能减法得到y
那么我们可以脑补一下最后一定是x加减到某个数d,然后从d开始+1 -1 和*2 交替进行得到y,这样的情况比较优,因为在小的时候尽量满足后来差得少
那么这个题就从y开始向下bfs,记录当前ny和ny离y的步数now,草我比赛的时候写成dfs了,想当然地以为一个数字一定是固定步数走到y的,虽然现在还没想到反例,不过bfs肯定是对的
状态数我比赛的时候脑补了一下,从y开始,y+1,y-1,y/2,大概最多是log^2个,官方题解写的logn不太明白
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,k,cnt,tot,cas;ll x,y,ans;
int a[maxl],b[maxl];
bool vis[maxl];
typedef pair<ll,ll> p;
set<ll> s;
queue<p> q;
inline void prework()
{
scanf("%lld%lld",&x,&y);
}
inline void inst(ll ny,ll now)
{
if(s.find(ny)!=s.end())
return;
s.insert(ny);
q.push({ny,now});
}
inline void mainwork()
{
if(x>=y)
{
ans=x-y;
return;
}
ans=y-x;
q.push({y,0ll});s.insert(y);
while(!q.empty())
{
p d=q.front();q.pop();
ll ny=d.first,now=d.second;
ans=min(ans,now+abs(ny-x));
if(ny<=x)
break;
if(ny&1)
inst(ny+1,now+1),inst(ny-1,now+1);
else
inst(ny/2,now+1);
}
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}