牛客小白月赛79

每次都不总结怎么进步

写写这次感触最深的D题吧

题目如下:

样例:

输入

3
1048575
1048576
1

输出

1
0
20

心路历程

本质就是对元素x进行 乘2、+1操作,问它最少需要多少次,能成为1<<20的倍数。

看到这个题目首先被它两个很大的数唬住,又想:给出的数是幂的形式,应该有什么巧妙之处。

果然,问GPT得知,2^20 可以用 1<<20(1左移20位)来表示。

这里就用到二进制了,后面比较我竟然还没想到呜呜

下一个问题,怎么判断一个数是 2^20 的倍数?(参考牛客解答)

二进制表示下 第一个1出现在20位及以后

最大的左移次数为20(至多20次就能解决问题,即输出数的范围为0~20)

以下图片代码摘自牛客解答【题解】牛客小白月赛79_ICPC/CCPC/NOIP/NOI刷题训练题单_牛客竞赛OJ (nowcoder.com)

#include <bits/stdc++.h>

using i64 = long long;
#define int long long

void solve(){
    int n, ans = 1e18;//ans = 20是一样的,不影响 //me:初始化为最大
    std::cin >> n;

    if(n >= (1ll << 20)){                       
        if(n % (1ll << 20) == 0){
            std::cout << 0 << '\n';
            return;
        }else{
            n %= (1ll << 20);
            for(int i = 0; i <= 20; ++i){ //me:20解释见上,至多20次
                int tt = n + i, cnt = 0;  //me:+i,此处i为+1的次数
                while(tt % 2 == 0){       //me:此处cnt为tt二进制表示下末尾0的个数
                    tt /= 2;
                    cnt++;
                }                      //me:20-cnt为需要左移次数,再+i为操作总次数 
                ans = std::min({20 - cnt + i, (1ll << 20) - n, ans});
            }                          //me:1ll<<-20-n为只+1的操作次数
        }
    }else{
        for(int i = 0; i <= 20; ++i){
            int tt = n + i, cnt = 0;
            while(tt % 2 == 0){
                tt /= 2;
                cnt++;
            }
            ans = std::min({ans, 20 - cnt + i, (1ll << 20) - n});
        }
    }

    std::cout << ans << '\n';
}
signed main() {

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr), std::cout.tie(nullptr);

    i64 _ = 1;
    std::cin >> _;

    while (_--) {
        solve();
    }

    return 0;
}

关于1ll

min()函数头文件algorithm

我的代码:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int fun(int n);
int main()
{
    int t,i;
    cin>>t;
    for(i = 0; i<t; i++){
        int n;
        cin>>n;
        cout<<fun(n)<<endl;
    }
    
    return 0;
}
int fun(int n)
{
    int i,ans = 20;         
    
    if(n % (1<<20) == 0)return 0;
    if(n > (1<<20))n %= 1<<20;
    for(i = 0; i<20; i++){
        int tt = n+i;
        int cnt = 0;
        while(tt % 2 == 0){
            tt /= 2;
            cnt++;
        }
        ans = min({20-cnt+i,(1<<20)-n,ans});
    }
    return ans;
        
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值