每次都不总结怎么进步
写写这次感触最深的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;
}