【1049 30 组合计数】 Counting Ones

传送门

题意

给定 \(n\) 求出从 \(1\sim n\) 中所有数字的所有位上出现的 \(1\) 的个数

数据范围

\(n\leq 2^{30}\)

题解

  • 依次考虑每一位上为\(1\)时可能有的数字个数数累计即可
  • 利用 \(mid\) 表示当前枚举到的位数,\(l,r\) 分别表示当前位左右两边的数字,\(p\) 用来通过模计算 \(r\) 等的值
  • 根据 \(mid\) 当前位上数分成三类
    • \(mid=0\),此时只有 \(l\)\(0\sim r\) 的时候有效,数字范围为 \(0\sim l\times p-1\),对答案的贡献为 \(l\times p\)
    • \(mid=1\),此时只有左边有 \(1\times p \sim l\times p\)\(l\times p\) 种,右边有\(0\sim r\)\(r+1\)
    • \(mid\geq 2\),此时即左边取 \(0\sim l\) 都可, \(p\) 包含右边 \(0\sim p-1\)\(p\) 种情况,贡献为 \((l+1)\times p\)

Code

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n; cin>>n;
	int l,r,mid;
	int ans=0,p=1;
	while(n/p){
		l=n/(p*10),mid=n/p%10,r=n%p;
		if(mid==0) ans+=l*p;
		else if(mid==1) ans+=l*p+r+1;
		else ans+=(l+1)*p;
		p*=10;
	}
	cout<<ans<<endl;
}
posted @ 2021-02-24 00:37  Hyx'  阅读(47)  评论(0)    收藏  举报