AtCoder Beginner Contest 188 F - +1-1x2

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;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/112505850