思路
这个题目据可以有两种思路,一种是递归构造答案的方法,一种是使用公式计算的的方法。第一种方法就是楼下个位大佬的做法,就是对于1,我们如果要的到后面的两组答案,一种是对这个数乘10,或是乘10后加一,这样就得到了新的两种答案,我们在对新的答案这样递归求解下去,直到大于输入的数 $ n $ 为止,这样我们在一边递归的时候一边记录的到的新数的数量,就可以解决这个问题了。
但是其实还有另一种方法,这个方法稍微慢一点,就是我们先求出不大于 $ n $ 的一个最大的只由 0,1
组成的数我们要怎么求这个数呢。废话不说上代码:
scanf("%lld",& n);
//将这个数的每一位分解
while(n!=0){
num.push_back(n%10);
n/=10;
}
for(int i=num.size()-1;i>=0;i--){
if(num[i]>1) //如果这个位子上的数大于1了,那么我们要求的那个数之后的几位就全是1了
flag=true;
if(flag)
maxn.push_back(1);
else{ //由于不能让所求的数超过n所以为了让这个数尽量大,如果是1的地方就是1,不是1的地方就是0,这样所求的数就不会超过原来的数
if(num[i]==1)
maxn.push_back(1);
else
maxn.push_back(0);
}
}
假如我们有一个10013027那么我们之后得到的数就是10011111,之后我们发现我们只需要对这个数进行一些1变成0或0变成1之类或者什么操作都不做的操作就可以得到我们想要的答案。对于例子中得到的数10011111,假如我们让第一个1变成0,那么后面的数不管进行什么操作的到的数一定是小于例子中的得到的数的,所以我们假设当前位置为i那么我们就可以用2^(len-i)
去更新答案 len
就是那个得到的数的长度。
Ps:这个算法这么解释有些地方其实是不对的,但是这些地方难以用言语解释清楚,所以你们可以自己去证明,但是这个思路的大体方向就是这样没错的。如果你想让程序跑得更快,可以用快速幂来优化。
完整代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
bool flag=false;
long long n;
vector <int> num,maxn; //注意:maxn是反过来存的
long long power(long long x,long long y)
{
long long ans=1,base=x;
while(y!=0){
if(y&1)
ans=ans*base;
base=base*base;
y>>=1;
}
return ans;
}
int main()
{
scanf("%lld",& n);
while(n!=0){
num.push_back(n%10);
n/=10;
}
for(int i=num.size()-1;i>=0;i--){
if(num[i]>1)
flag=true;
if(flag)
maxn.push_back(1);
else{
if(num[i]==1)
maxn.push_back(1);
else
maxn.push_back(0);
}
}
long long ans=0;
for(register int i=0;i<(int)maxn.size();i++){
if(maxn[i]==1){
ans+=power(2,(int)maxn.size()-1-i);
}
}
printf("%lld\n",ans);
return 0;
}