洛谷 P3152 正整数序列

题目大意:输入一个正整数n(1<=n<=10^9)以此构造一个正整数序列1,2,3,4,...,n,问最少几次操作(任意选取几个数,共同减去一个相同的正整数)可以将该序列归零。

思路1:对于一个单调递增的线段,我们对他进行几次操作可以让他回到x轴上

 c98250fdd0fc440c978fbbb40b249cbf.png

 我们可以对线段的任意多条子线段或者一点进行上下位移(相同的距离)

不难发现将其对半然后移动,就可以变成两个一模一样的1/2线段,接下来的每一次操作 都相当于执行了两次操作。因为只能上下移动相同的距离所以不会出现接下来每次操作 能产生更高的效率。

2a01f740140e49d78299fe56c0351986.png

于是我们以此类推就能将线段分成点,让这些点全部回归x轴了。

#include <bits/stdc++.h>
using namespace std;

int n;

inline int recur(int x){
    if(x==1)return 1;
    return recur(x/2)+1;//每次执行对半分的时候相当于进行了一次操作
}

int main(){
    cin>>n;
    cout<<recur(n);
    return 0;
}

同时很明显,每次对新的数进行二分,即((n/2)/2)/2。相当于2^x=n,x+1为多少

如果2^x太大了那就直接输出x就可以了。

#include <bits/stdc++.h>
using namespace std;

int n;

int main(){
    cin>>n;
    for(int i=0;;i++)
        if(pow(2,i)==n){
            cout<<i+1;
            break;
        }else if(pow(2,i)>n){
            cout<<i;
            break;
        }
    return 0;
}

根据if和else if两者条件来看很明显是在求log2n,故代码可以进一步简洁。

#include <bits/stdc++.h>
using namespace std;

int n;

int main(){
    cin>>n;
    cout<<(int)log2(n)+1;
    return 0;
}

思路2:将正整数序列全部变成二进制,每次操作让0的数量尽可能的变多

0001 0010 0011 0100 0101 0110 0111 

每次直接去掉2^0~2^2,最多三次操作 比如0001 0011 0101 0111这四个数都有0001,直接去掉最后一位。可见没有比这种方法增加0的速度更快。

故答案直接输出最高位1所在的位置,如最高位1在第三位,则输出3,利用位运算可以快速算出答案。

并且最高位1只有可能出现在最大的数上面

故代码

int n,count=1,ans=-1;

cin>>n;

while(n){

if(n&1)ans=count;

n>>=1;

count++;

}

cout<<ans;

return 0;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值