zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 188 F

    题目描述

    给你两个数 (x),(y)

    可以对 (x) 进行 (+1,-1)( imes 2) 的操作

    问最少操作多少次后变为 (y)

    (x,y leq 10^{18})

    分析

    将问题转化为从 (y) 变为 (x),可以进行 (+1,-1)(div 2) 的操作

    之所以这样做,是因为转化题意之后操作更受约束

    如果当前值为偶数,则只能除以 (2)

    如果当前值为奇数,则只能执行加 (1) 或减 (1) ,再除以 (2)

    因为如果要加更多的数,完全可以在除以 (2) 之后再加

    相比之下,你可以随时加 (1) 或乘 (2),所以有更多的分支

    如果你把它想象成一个根树遍历,那就好像如何重复地找到父对象要比探索所有子对象简单得多

    这样做复杂度看起来还是 (2^{logy}=y)

    实际上,若 (y) 为偶数,只会有 (y/2) 一个分支

    (y) 为奇数,会有 ((y+1)/2)((y-1)/2) 两个分支

    而且这两个数是相邻的,设为 (a,a+1)

    如果 (a) 为奇数,下一层递归会有 ((a+1)/2,(a-1)/2,(a+1)/2) 三个分支

    如果我们采用记忆化搜索的方式,只会递归到两个分支

    同样若 (a) 为偶数,下一层递归会有 (a/2,a/2,(a+2)/2) 三个分支

    记忆化后也变为了两个分支

    因为每一次都会除以 (2),所以最多递归 (log)

    而每一层只有两个不同的数,所以最终的状态是 (log) 级别的

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    long long n,m;
    std::map<long long,long long>mp;
    long long dfs(rg long long now){
    	if(mp.find(now)!=mp.end()) return mp[now];
    	if(now<=n) return n-now;
    	rg long long nans=now-n;
    	if(now&1){
    		nans=std::min(nans,std::min(dfs((now-1)/2),dfs((now+1)/2))+2);
    	} else {
    		nans=std::min(nans,dfs(now/2)+1);
    	}
    	return mp[now]=nans;
    }
    int main(){
    	scanf("%lld%lld",&n,&m);
    	if(n>=m){
    		printf("%lld
    ",n-m);
    		return 0;
    	}
    	printf("%lld
    ",dfs(m));
    	return 0;
    }
    
  • 相关阅读:
    文件操作
    set集合,深浅拷贝
    is 和 == 区别 id()函数
    字典
    列表
    基本数据类型
    第十二章 if测试和语法规则
    第十一章 赋值、表达式和打印
    第十章 python语句简介
    第九章元组、文件及其他
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14260518.html
Copyright © 2011-2022 走看看