TOJ 2294 POJ 3286 How many 0's? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html

http://poj.org/problem?id=3284

题外话:集训结束,回学校了。在宿舍看了这题,没什么好想法,去洗澡了。转了两个澡堂都特么没开。。倒是在路上把这题想了。用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级。

题意:给定两个数a和b,从a写到b,问一共写了多少个0。

分析:当然先转化为求0..a写多少个0。网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不能取0,取0这位也没了),右边则可以任意取,如果取a,则右边只能取0到右边最大值。如果本来不是0,就是没什么限制地取。

然后我是类似上次49那题数位dp的做法。f[i]表示长度为i的数串有多少个0(没限制),g[i]表示长度为i的数串,第一位为0,有多少个0。

一样转化为求0..a写多少0。考虑a,假设长度为len,最高位填0的情况是g[len],最高位为x,那么1..x-1这些可以补在长度为len-1的数串前面,即(x-1)*f[len-1]。然后最高位就是x了,继续枚举每位下去(每次枚举的当前位,是计算当前位小于当前位的最大值的方案数,然后到下一位时,已经枚举过的都是当做对应的最大值)。如果这一位是x(!= 0),那么可以填1..x-1 * f[restlen],当前位填0,那么后面可以任意填。这一位是0,那么之后只能填从0到之后的最大值。(反正就是这么个意思。。意会一下吧。。)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5
 6 #define debug 0
 7 #define bug 0
 8 long long a, b;
 9 long long f[40], g[40];
10 int d[40];
11 long long G(int x)
12 {
13     if (x == 1) return 1;
14     return G(x-1) + f[x-2] * 9;  //当前位填0,那么可以是下一位填1-9,或是下一位填0的相同情况(递归)
15 }
16 void init()
17 {
18     f[0] = 0;
19     long long exp = 1;
20     for (int i = 1; i < 40; i++){  //这一位任填0-9,所以原来的变为10倍,同时计算这位为0的总数(之前的任填)。
21         f[i] = f[i-1] * 10 + exp;
22         exp = exp * 10;
23     }
24     for (int i = 1; i < 40; i++)
25         g[i] = G(i);
26 }
27 long long cal(long long x)
28 {
29     if (debug) printf("%lld\n", x);
30     if (x == -1) return 0;
31     if (x == 0) return 1;
32     int len = 0;
33     while(x){
34         d[len++] = x % 10;
35         x /= 10;
36     }
37     long long ret = g[len] + f[len-1] * (d[len-1]-1);
38     if (debug) printf("%lld\n", ret);
39     long long exp = 1;
40     for (int i = 0; i < len-2; i++)
41         exp = exp * 10;
42     for (int i = len-2; i >= 0; i--){
43         if (d[i]) ret = ret + exp;
44         else{
45             long long tmp = 0;
46             for (int j = i-1; j >= 0; j --)
47                 tmp = tmp * 10 + d[j];
48             ret = ret + tmp + 1;
49         }
50         exp = exp / 10;
51         ret = ret + f[i] * d[i];
52     }
53     if (debug) printf("%lld\n", ret);
54     return ret;
55 }
56 int main()
57 {
58     init();
59     while(scanf("%lld %lld", &a, &b))
60     {
61         if (a < 0 || b < 0) break;
62         if (bug) printf("%lld %lld\n", cal(b), cal(a-1));
63         printf("%lld\n", cal(b) - cal(a-1));
64     }
65     return 0;
66 }

TOJ 2294 POJ 3286 How many 0's? 数位dp

时间: 2024-12-28 17:31:05

TOJ 2294 POJ 3286 How many 0's? 数位dp的相关文章

POJ - 3286 - How many 0&#39;s? 【数位DP】

How many 0's? Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0's will he writ

poj 3286 How many 0&#39;s? 按位统计

题意: 给m<=n,求从m写到n,一共写多少个0. 分析: 按位算当某位是0时左边有多少种情况,右边有多少种情况,注意左边的情况数为-1时(这时遍历到最高位)是为了把右边多加的情况减去,也就是把0作为开头时的情况减去. 代码: //poj 3286 //sep9 #include<iostream> using namespace std; typedef __int64 ll; ll b[16]; ll f(ll n) { ll left,m,ans=0; for(int i=1;i&

POJ 3286 How many 0&#39;s?(多少0?)

POJ 3286 How many 0's?(多少0?) Time Limit: 1000MS   Memory Limit: 65536K [Description] [题目描述] A Benedict monk No.16 writes down the decimal representations of all natural numbers between and including m and n, m ≤ n. How many 0's will he write down? 一个

POJ 3286 How many 0&#39;s?

题目大意: 计算[m,n]之间所有数字有多少个零. 解题思路: 可以用[0,m)之间和[0,n]之间有多少个零然后作差. 规律是计算所有位置在到当前数时有多少个零. 下面是代码:   #include <set> #include <map> #include <queue> #include <math.h> #include <vector> #include <string> #include <stdio.h> #

POJ 3286 How many 0&#39;s(数位DP模板)

题目链接:http://poj.org/problem?id=3286 题目大意: 输入n,m,求[n,m]的所有数字中,0出现的总数是多少,前导零不算. 解题思路: 模板题,设dp[pos][num],pos为数位,num为当前0的数目,然后套数位DP模板即可. 还有之前的一些思考: 关于数位DP求0时,dp下标记录num有什么作用,num不是与后面的0的个数无关吗?是的,在(!limit&&!lead)的情况下,前面有多少0是不影响后面可以出现多少0的.但是,比如说dp[pos][nu

POJ 3208 Apocalypse Someday 二分答案+数位DP

这题应该是POJ最强大的一道数位DP了吧 正解是AC自动机 不会 还是写数位DP吧 题目大意:我们令含有666的数字为不吉利数字,则可以得到一个递增数列: {an}=666,1666,2666,3666,4666,5666,6660,6661,.... 给定n,求an 首先我们把这个问题转化成另一个问题:给定n,求1~n中有多少个数含有666 解决了这个问题,把原问题二分答案即可 首先预处理f数组,令 f[i][0]表示i位数中首位不为6且不含666的数的数量 f[i][1]表示i位数中首位连续

poj 3286 统计0的个数

1 #include <iostream> 2 3 using namespace std; 4 long long p; 5 long long a[20]; 6 long long solve(long long n){ 7 long long left,m,sum =0; 8 for(int i=1;i<12;i++){ 9 left = n/a[i]-1; 10 sum += left*a[i-1]; 11 m = (n%a[i]-n%a[i-1])/a[i-1]; 12 if(

poj 3009 Curling 2.0 【DFS】

题意:从2出发,要到达3, 0可以通过,碰到1要停止,并且1处要变成0, 并且从起点开始沿着一个方向要一直前进,直至碰到1(或者3)处才能停止,(就是反射来反射去知道反射经过3).如果反射10次还不能到达3,就输出-1. 策略:深搜. 易错点,方向不容易掌握,并且,出题人把n, m顺序反了. 代码: #include<stdio.h> #include<string.h> int map[25][25]; int ans, n, m; const int dir[4][2] = {

POJ 3628 Bookshelf 2 0/1背包和DFS两种解法

题目链接:POJ 3628 Bookshelf 2 Bookshelf 2 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7462   Accepted: 3436 Description Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly,