UVA 1640 The Counting Problem(统计题,找规律 + dfs)

大体题意:

告诉你两个数a和b 问你a到b 区间内的数中,0,1,2,3,4,5,6,7,8,9每个数字出现了几次?

思路:

我们先写一个暴力的程序会找到一个规律:

除了0以外的9个数字:

9以内有1个 = num[1]

99以内有20个 = num[2]

999以内的有300个 = num[3]

9999以内的有4000个 = num[4]

依次类推:

我们可以根据这个规律来写:

比如说997内 找4的个数

百分位为0 1 2 3 5 6 7 8 的都有num[2]个 。

在来算百分位为4的,去掉9以后  为97,那么就有98个4.

在dfs  97中4 的个数。

在算百分位为9的,直接加dfs 97中4的个数即可。

这样1~9都算完了,还有0的没算。

我们可以算一个数 中所有数字出现了几次,用总和减去1~9的即可:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define Siz(x) (int)x.size()

using namespace std;
typedef long long LL;
int num[] = {1,1,20,300,4000,50000,600000,7000000,80000000,900000000};
int getlen(int x){
    if (x == 0) return 1;
    int ans=0;
    while(x) {
        ++ans;
        x/=10;
    }
    return ans;
}
int get_first(int x){
    if (x == 0) return 0;
    while(x/10){
        x/=10;
    }
    return x;
}
LL getall(int x){
    LL ans = 0;
    int cur = 1;
    int L = 0,R = 9;
    while( !(x >= L && x <= R) ){
        ans += cur*(R-L+1);
        L = R+1;
        cur++;
        R = R*10+9;
    }
    ans += (x-L+1)*cur;
    return ans;
}

int dfs(int x,int v,int len){

	if (len == 1){
        if (x >= v) return 1;
        return 0;
	}
    int ans = 0;
    int f = get_first(x);
    int v2 = 1;
    for (int i = 0; i < len-1; ++i) v2*=10;
    int x2 = x - f*v2;
    if (f > v){
        for (int i = f-1; i > v; --i){
            ans += num[len-1];
        }
        for (int i = v-1; i >= 0; --i)ans += num[len-1];

        ans += v2 + num[len-1];
        ans += dfs(x2,v,getlen(x2));
    }
    else if (f == v){
        for (int i = v-1; i >= 0; --i)ans += num[len-1];
        ans += x2+1 + dfs(x2,v,getlen(x2));
    }
    else {
        for (int i = f-1; i >= 0; --i)ans += num[len-1];
        ans += dfs(x2,v,getlen(x2));
    }
    return ans;
}

vector<int>ans;
int main(){
//    freopen("out.txt","w",stdout);
    int a,b;

    while(~scanf("%d %d",&a, &b) && (a||b)){
        if (a > b) swap(a,b);
        ans.clear();
        LL sum = 0LL;
        for (int i = 1; i <= 9; ++i){
            ans.push_back(dfs(b,i,getlen(b)) - dfs(a-1,i,getlen(a-1)));
            sum += ans.back();
        }
        ans.push_back(getall(b) - getall(a-1));
        printf("%lld",ans.back()-sum);
        for (int i = 0; i < 9; ++i)printf(" %d",ans[i]);
        putchar('\n');
    }
    return 0;
}
/**
1496 1403
**/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值