zoukankan      html  css  js  c++  java
  • [JZOJ] 01知多少

    (color{red}{mathcal{Description}})

    (1)(n) 有多少个数的十进制表示中只由 (0)(1) 构成.

    (color{red}{mathcal{Input Format}})

    输入一个整数 (n).

    (color{red}{mathcal{Output Format}})

    输出一个整数.

    (color{red}{mathcal{DataSize Agreement}})

    (1 leq n leq 10^9)

    (color{red}{mathcal{Solution}})

    一道比较巧妙的题目

    首先看到就想到暴力,但是看了数据范围绝对不可做,所以先打了个表(但是后来才发现根本不需要)

    想了一下,看到 (0)(1) ,不难想到二进制,但是这怎么和二进制扯上关系呢

    这里介绍 (3) 种方法

    (color{blue}{mathcal{Solution }1})

    因为满足要求的数只由 (0)(1) 构成,我们可以通过递归计算出每次符合条件的数,直到大于 (n) 就停止

    (color{blue}{mathcal{Code}})

    #include <bits/stdc++.h>
    #define LL long long
    #define reg register
    
    using namespace std;
    
    int N, Ans = 1;
    
    void dfs(int sum) {
      if (sum * 10 > N) return ;
      Ans++;
      dfs(sum * 10);
      if (sum * 10 + 1 > N) return ;
      Ans++;
      dfs(sum * 10 + 1);
    }
    
    int main() {
      scanf("%d", &N);
      dfs(1);
      printf("%d
    ", Ans);
      
      return 0;
    }
    
    

    (color{blue}{mathcal{Solution }2})

    我们尝试把十进制非零自然数从小到大进行二进制的转换:

    ((1)_{10} - (1)_2)
    ((2)_{10} - (10)_2)
    ((3)_{10} - (11)_2)
    ((4)_{10} - (100)_2)

    对照打出的表可以发现,在区间 ([1,n]) 范围内,十进制 (i) 的二进制数恰好是第 (i) 个符合条件的数!

    得到这样的规律以后就非常简单了

    (color{blue}{mathcal{Code}})

    /*遍历每个十进制数,将该数先转换成二进制的形式,然后再把二进制形式转换成一个01构成的十进制数, 一一对应,超过n就结束 
     1=>1  2=>10 3==>11  4=>100 5=>101  6=>110  .... 
    个数  二进制  十进制 
      1      1      1
      2      10     10
      3      11     11
      4      100    100
      5      101    101
      6      110    110
      7      111    111
      8      1000   1000
      9      1001   1001
    */
    
    #include <bits/stdc++.h>
    #define LL long long
    #define reg register
    
    using namespace std;
    
    const int kSize = 10;
    
    int N, num[kSize];
    
    int main() {
      scanf("%d", &N);
      for (reg int i = 1; ; ++i) {
      	int s = i, size = 0;
      	while (s) { num[++size] = s % 2; s >>= 1;}
      	s = 0;
      	for (reg int j = size; j >= 1; --j)
      	  s = s * 10 + num[j];
      	if (s > N) return printf("%d
    ", i - 1), 0;
      }
      return 0;
    }
    
    

    (color{blue}{mathcal{Solution }3})

    数学方法,对于一个整数 (m) ,如果它的第 (i) 位大于等于 (1),那么就有 (2^{i-1}) 种方案

    具体看代码

    (color{blue}{mathcal{Code}})

    #include <bits/stdc++.h>
    #define LL long long
    #define reg register
    
    using namespace std;
    
    const int kSize = 10;
    
    int N, Ans = 0, num[kSize];
    
    int Qpow(int n, int k) {
      int ret = 1;
      for (; k; k >>= 1, n = n * n) if (k & 1) ret *= n;
      return ret;
    }
    
    int main() {
      scanf("%d", &N);
      int size = 0;
      while (N) { num[++size] = N % 10; N /= 10; }
      for (reg int i = size; i >= 1; --i) { //从高位到低位
      	if (num[i] > 1) return printf("%d
    ", Ans + Qpow(2, i) - 1), 0; //数位上不是0就是1, 所以每一位两种情况  2^i个数, 但是0不算,所以减一 
      	else
      	  if (num[i] == 1) Ans += Qpow(2, i - 1);
      }
      printf("%d
    ", Ans);
      return 0;
    }
    
    
  • 相关阅读:
    asp Excel导入数据库
    Excel导出函数
    asp精简checkbox全选代码
    一个操作读写已存在excel 文件的例子
    asp中实现网络打印功能
    asp操作excel 技术总结
    asp初学者常用的代码
    asp连接各种其他数据库 的方法
    asp得到地址栏里"?"以后的字串
    asp判断今天是星期几
  • 原文地址:https://www.cnblogs.com/1miharu/p/11327755.html
Copyright © 2011-2022 走看看