51nod1042(0-x出现次数&分治)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1042
题意:中文题诶~
思路:这道题和前面的51nod1009好像,直接套用那个算法也是能ac的,不过我还是喜欢换个口味;
求a, b之间个数字出现的次数。可以由分治的思想,先求出他们在0~b出现的次数, 再求出在0~a-1出现的次数,前者减去后者即为答案;
然而如何求出0~x各个数字出现的次数我是看了一本书上的方法才会的,这里直接给出代码好了,随便带入一组数据也不难验证其正确性,所以也就不多说啦。。。
代码:
1 #include <bits/stdc++.h>
2 #define ll long long
3 #define MAXN 10
4 using namespace std;
5
6 ll value=1; //***value记录当前的权值
7 ll vis[MAXN]; //***vis[i]存储0到x中i出现的次数
8
9 void deal(ll n){
10 if(n<=0){
11 return;
12 }
13 ll one=n%10; //***one, ten分别表示当前n的个位和高位
14 n/=10;
15 ll ten=n;
16 for(int i=0; i<=one; i++){ //***累计当前个位出现的次数
17 vis[i]+=value;
18 }
19 while(ten){
20 vis[ten%10]+=(one+1)*value; //***累计当前高位出现的次数
21 ten/=10;
22 }
23 for(int i=0; i<10; i++){ //***累计权值范围数出现的次数
24 vis[i]+=n*value; //***注意这里会累加到0开头的情况
25 }
26 vis[0]-=value; //***将第一位是0的情况排除
27 value*=10;
28 deal(n-1);
29 }
30
31 int main(void){
32 ll a, b;
33 cin >> a >> b;
34 if(a>b){
35 swap(a, b);
36 }
37 deal(b);
38 value=-1;
39 deal(a-1);
40 for(int i=0; i<10; i++){
41 cout << vis[i] << endl;
42 }
43 return 0;
44 }
还是写一下套用1009ac的代码好了~
代码:
1 #include <bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4
5 ll deal(ll n, ll key){
6 ll x=n, cnt=1, ans=0;
7 while(n){
8 if(!key){
9 ans-=cnt;
10 }
11 ll gg=n%10;
12 ll num=x/(cnt*10);
13 if(gg<key){
14 ans+=num*cnt;
15 }else if(gg==key){
16 ans+=num*cnt+x%cnt+1;
17 }else{
18 ans+=(num+1)*cnt;
19 }
20 cnt*=10;
21 n/=10;
22 }
23 return ans;
24 }
25
26 int main(void){
27 ll a, b;
28 cin >> a >> b;
29 if(a>b){
30 swap(a, b);
31 }
32 for(ll i=0; i<10; i++){
33 cout << deal(b, i)-deal(a-1, i) << endl;
34 }
35 return 0;
36 }
我就是我,颜色不一样的烟火 --- geloutingyu