UVa 1640 - The Counting Problem(数论)

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4515

题意:

给出整数a、b,统计a和b(包含a和b)之间的整数中,数字0,1,2,3,4,5,6,7,8,9分别出现了多少次。1≤a,b≤1e8。

分析:

解决这类题目的第一步一般都是:令f(n,d)表示0~n中数字d出现的次数,则所求的就是f(b,d)-f(a-1,d)。
例如,要统计0~234中4的个数,可以分成几个区间:

范围                    模板集
0~9                    *
10~99                **
100~199            1**
200~229            20*,21*,22*
230~234            230,231,232,233,234

上表中的“模板”指的是一些整数的集合,其中字符“*”表示“任意字符”。例如,1**表示以1开头的任意3位数。
因为后两个数字完全任意,所以“个位和十位”中每个数字出现的次数是均等的。
换句话说,在模板1**所对应的100个整数的200个“个位和十位”数字中,0~9各有20个。
而这些数的百位总是1,因此得到:模板1**对应的100个整数包含数字0,2~9各20个,数字1有120个。
这样,只需把0~n分成若干个区间,算出每个区间中各个模板所对应的整数包含每个数字各多少次,就能解决原问题了。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3
 4 const int UP = 10;
 5 int pow10[UP], amt[UP];
 6
 7 int f(int n, int d) {
 8     int res = 0;
 9     char s[99];
10     sprintf(s, "%d", n);
11     int len = strlen(s);
12
13     for(int i = 1; i < len; i++) {
14         if(i == 1) res++;
15         else {
16             res += 9 * amt[i-1];
17             if(d > 0) res += pow10[i-1];
18         }
19     }
20
21     int pre = 0;
22     for(int i = 0; i < len; i++) {
23         int L = 0, R = s[i]-‘0‘;
24         if(i == 0 && len > 1) L = 1;
25         for(int digit = L; digit < R; digit++) {
26             res += amt[len-1-i] + pre * pow10[len-1-i];
27             if(digit == d) res += pow10[len-1-i];
28         }
29         if(s[i]-‘0‘ == d) pre++;
30     }
31     return res + pre;
32 }
33
34 int main() {
35     pow10[0] = 1;
36     for(int i = 1; i < UP; i++) {
37         pow10[i] = pow10[i-1] * 10;
38         amt[i] = pow10[i] * i / 10;
39     }
40     int a, b;
41     while(scanf("%d%d", &a, &b) && a) {
42         if(a > b) b += a, a = b-a, b -= a;
43         printf("%d", f(b,0) - f(a-1,0));
44         for(int i = 1; i < 10; i++) printf(" %d", f(b,i) - f(a-1,i));
45         printf("\n");
46     }
47     return 0;
48 }

原文地址:https://www.cnblogs.com/hkxy125/p/9631697.html

时间: 2024-08-01 15:06:40

UVa 1640 - The Counting Problem(数论)的相关文章

UVA 1640 The Counting Problem UVA1640 求[a,b]或者[b,a]区间内0~9在里面各个数的数位上出现的总次数。

/** 题目:UVA 1640 The Counting Problem UVA1640 链接:https://vjudge.net/problem/UVA-1640 题意:求[a,b]或者[b,a]区间内0~9在里面各个数的数位上出现的总次数. 思路:数位dp: dp[leadzero][i][j][k]表示前面是否选过非0数,即i长度之后可以第一个出现0,而不是前导0,长度为i,前面出现j,k次,j出现的次数. */ #include<iostream> #include<cstri

UVA 1640 The Counting Problem

https://vjudge.net/problem/UVA-1640 题意:统计区间[l,r]中0——9的出现次数 数位DP 注意删除前导0 #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int ans[10],a[10],dp[10][10],bit[10]; int dfs(int dep,int ty,bool l

UVa 1640 The Counting Problem (数位DP)

题目 题目大意 给出\(a\).\(b\), 统计\(a\)和\(b\)(包含\(a\)和\(b\))之间的整数中, 数字\(0, 1, 2, 3, 4, 5, 6, 7, 8, 9\)分别出现了多少次.\(1 ≤ a, b ≤ 10^8\).注意, \(a\)有可能大于\(b\). 题解 设\(f_d(n)\)表示\(0 \cdots n\)中数字\(d\)出现的个数, 则求的是\(f_d(a) - f_d(b - 1)\). 暴力显然是会\(TLE\)的, 我们可以分段来求.例如我们要求\(

UVA 11490 - Just Another Problem(数论)

11490 - Just Another Problem 题目链接 题意:有S个士兵,排成一个矩阵,矩阵中可以有两个洞,要求两个洞上下左右厚度一样,问能缺少士兵的情况数. 思路:推推公式,设厚度为a, 正方形为i, 那么(3 a + 2 i) (2 a + i) = S + 2 i i; 化简一下得到6 i i + 7 a i = S 由于S很大,所以去枚举厚度,这样只要枚举到sqrt(S)就够了,复杂度可以接受 代码: #include <stdio.h> #include <stri

UVA 11401 - Triangle Counting(数论+计数问题)

题目链接:11401 - Triangle Counting 题意:有1,2,3....n的边,求最多能组成的三角形个数. 思路:利用三角形不等式,设最大边为x,那么y + z > x 得 x - y < z < x 然后y取取值,可以从1取到x - 1,y为n时候,有n - 1个解,那么总和为0 + 1 + 2 +...+ (x - 2) = (x - 1) * ( x- 2) / 2; 然后扣除掉重复的y = z的情况,在y > x / 2时,每个y取值会出现一次y = z.

UVA 1363 - Joseph&#39;s Problem(数论)

UVA 1363 - Joseph's Problem 题目链接 题意:给定n, k,求出∑ni=1(k mod i) 思路:由于n和k都很大,直接暴力是行不通的,然后在纸上画了一些情况,就发现其实对于k/i相同的那些项是形成等差数列的,于是就可以把整个序列进行拆分成[k,k/2],[k/2, k/3], [k/3,k/4]...k[k/a, k/b]这样的等差数列,利用大步小步算法思想,这里a枚举到sqrt(k)就可以了,这样就还剩下[1,k/a]的序列需要去枚举,总时间复杂度为O(sqrt(

SWJTU2017-6月月赛 G-A Easy Counting Problem[数论][乘法逆元]

传送门:http://www.swjtuoj.cn/problem/2397/ 题解:产生交点的条件为4个点构成四边形对角线产生交点,最大解当产生的交点位置完全不相同时存在.答案为$C_{\text{n}}^4$ 计算组合数时需要使用乘法逆元 代码: 1 #define _CRT_SECURE_NO_DEPRECATE 2 #pragma comment(linker, "/STACK:102400000,102400000") 3 #include<iostream> 4

uva 11401 - Triangle Counting(数论)

题目链接:uva 11401 - Triangle Counting 题目大意:有多少种方法可以从1,2,3...n中选出3个不同的数组成三角形,给出n,求种数. 解题思路:加法原理,设最大边为x的三角形有c(x)个,那么另外两条边长分别为y和z,根据三角形的形式可以的y+z>x,所以z的范围即为x?y<z<x 根据这个不等式可以得到每个y值所对应的z值个数,为等差数列,所以 c(x)=(x?1)?(x?2)2??x?12?2 然后根据递推:f(n)=∑i=1nc(i) 代码 #incl

UVA - 11401 - Triangle Counting (递推!)

UVA - 11401 Triangle Counting Time Limit: 1000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu Submit Status Description Problem G Triangle Counting Input: Standard Input Output: Standard Output You are given n rods of length 1, 2-, n. You have