题目描述
请统计某个给定范围[L, R]的所有整数中,数字2出现的次数。
比如给定范围[2, 22],数字2在数2中出现了1次,在数12中出现1次,在数20中出现1次,在数21中出现1次,在数22中出现2次,所以数字2在该范围内一共出现了6次。
输入描述:
输入共1行,为两个正整数L和R,之间用一个空格隔开。
输出描述:
输出共1行,表示数字2出现的次数。
示例1
输入
2 22
输出
6
示例2
输入
2 100
输出
20
备注:
解答
这道题很显然是削弱版的51nod P1042。那么显然我们需要使用数位DP解题。
思路大致是这样的:
对于每一个数字,考虑三种影响关系:
1. 它对低位的影响
2. 它对高位的影响
3. 高位对低位的影响
然后在递归中实现这三种关系的计算即可。
代码:
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; #define CLR(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define LL long long void dp(LL n , LL m , LL *c) { LL x = n % 10; LL y = n / 10; for (int i = 0 ; i <= x ; i++) c[i] += m; //当前位对低位的影响,每个都是0~9的范围 for (int i = 0 ; i <= 9 ; i++) c[i] += m * y; //当前位对的高位影响(高位不为0,在上一个循环中算过) c[0] -= m; //排除前导0的情况 LL t = y; while (t) //高位对低位的影响,即都为最大限制数 { c[t % 10] += (x+1) * m; //算上0 t /= 10; } if (y) dp(y-1 , m*10 , c); //y值在上个while中算过,算下一个未限制数 } int main() { LL r,l; LL a[10] = {0}; LL b[10] = {0}; scanf ("%lld %lld",&l,&r); dp(r , 1 , a); dp(l-1 , 1 , b); printf("%lld\n",a[2]-b[2]); return 0; }