数位DP-HDU-3555-Bomb
来源:互联网 发布:少男的喜欢lofter乐乎 编辑:程序博客网 时间:2024/05/22 22:23
Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 11379 Accepted Submission(s): 4044
Problem Description
The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence “49”, the power of the blast would add one point.
Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?
Input
The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.
The input terminates by end of file marker.
Output
For each test case, output an integer indicating the final points of the power.
Sample Input
3
1
50
500
Sample Output
0
1
15
Hint
From 1 to 500, the numbers that include the sub-sequence “49” are “49”,”149”,”249”,”349”,”449”,”490”,”491”,”492”,”493”,”494”,”495”,”496”,”497”,”498”,”499”,
so the answer is 15.
Author
fatboy_cw@WHU
Source
2010 ACM-ICPC Multi-University Training Contest(12)——Host by WHU
题意是给一个数N,要求1到N中,数位中出现连续的49的数有多少个,比如49,149,249,499之类的。
初次接触数位DP,真的是头都大了,一开始自己瞎想,弄个dp[size][start]来存第size位是start的情况下满足题意的数的个数,最后由于不好处理,没法输出。
后来只好又去查了查,看了些博客,总算把这道题看懂,大致还是分情况讨论了,其实和DFS差不多的感觉,不过看见有个人用DFA做这道题,有点不明觉厉。
先将N按数位存在num[]数组中。
用dp[i][0]存储0~99..9(i个9)中不满足题意的数的个数。
用dp[i][1]存储同上的范围中不满足题意的以9作为第i位数的个数。
用dp[i][2]存储同上的范围中满足题意的数的个数。
当求dp[i][0]时,由于第i位可以取0~9,同时后i-1位必须不满足,所以先加上十个dp[i-1][0],而后,由于第i位取4,第i-1位取9的时候,不满足,所以还要减去dp[i-1][1]。
那么dp[i][0]=dp[i-1][0]*10-dp[i-1][1]。
当求dp[i][1]时,第i位可以取9,那么只要在后i-1位的不满足题意的数前加一个9即可。
即dp[i][1]=dp[i-1][0]。
当求dp[i][2]时,第i位可以取0~9,那么如果后i-1位已经满足条件,随便取第i位都可以,那么先加上10个dp[i-1][2],同时如果第i位取4,第i-1位取9,那么将新增dp[i-1][1]个满足题意的数,加上。
得到dp[i][2]=10*dp[i-1][2]+dp[i-1][1]。
至此可以预处理出题中要求范围的所有dp[i][0~2]。
那么对于一个数N,又要怎样处理呢。
首先我们已经把N存在了num[]数组中,并且能够得到其长度size,令最终输出为sum,初始值为0。
处理方式是从最高位向最低位累加,加到第i位时,前size-i位都取了最大的值作为当前的参考。
如果当前已经处理到第i位(i>=1),那么如果后i-1位是符合的,第i位随便取也能符合(当然不能超过num[i]),那么先加上dp[i-1][2] x num[i]。同时,如果在第i位之前就已经在num[]中出现过连续49,那么这后i位随便取都能符合题意,由于已经加了num[i]个dp[i-1][2],所以还要加上num[i]个dp[i-1][0](由数组定义可知dp[i-1][0]+dp[i-1][2]是一定等于99..9(i-1个)的)。如果第i位之前没有出现过49,那么如果num[i]>4,当第i位取4,第i-1位取9时,又能获得dp[i-1][1]个符合题意的数,所以再加上dp[i-1][1](当然,如果已经出现了49,就不要重复加了)。
一直处理到第1位,此时如果前面出现过49,就加一(因为是没有考虑其本身的)。
输出sum即可。
在做了HDU2089之后,我又用我上述的dp[size][start]的方法做了一次这道题,时间降到15ms。
附上2089方法详解:http://blog.csdn.net/roy_yuan/article/details/49500063
原方法
//// main.cpp// 数位DP-D-Bomb//// Created by 袁子涵 on 15/10/29.// Copyright © 2015年 袁子涵. All rights reserved.//// 62ms 1604KB#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>#include <stdlib.h>using namespace std;int T;long long int dp[20][3],N;int num[20];void handle(){ dp[0][0]=1; for (int i=1; i<=18; i++) { dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; dp[i][1]=dp[i-1][0]; dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; }}long long int DP(){ int size=0; long long int temp=N; memset(num, 0, sizeof(num)); while (temp) { num[++size]=temp%10; temp/=10; } bool flag=0; for (int i=size; i>0; i--) { temp+=dp[i-1][2]*num[i]; if (flag) temp+=dp[i-1][0]*num[i]; else if (num[i]>4) temp+=dp[i-1][1]; if (num[i+1]==4 && num[i]==9) flag=1; } if (flag) temp++; return temp;}int main(int argc, const char * argv[]) { cin >> T; memset(dp, 0, sizeof(dp)); handle(); while (T--) { cin >> N; long long int out=0; out=DP(); cout << out << endl; } return 0;}
最新
//// main.cpp// 数位DP-D-Bomb-New//// Created by 袁子涵 on 15/10/30.// Copyright © 2015年 袁子涵. All rights reserved.//// 15ms 1596KB#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>#include <math.h>#include <iostream>using namespace std;int T;long long int N,dp[20][10];void handle(){ for (int i=0; i<10; i++) dp[1][i]=0; for (int i=2; i<=18; i++) { for (int j=0; j<=9; j++) { dp[i][j]=0; if (j==4) { for (int k=0; k<=9; k++) { if (k==9) dp[i][j]+=(long long int )pow(10, i-2); else dp[i][j]+=dp[i-1][k]; } continue; } else for (int k=0; k<=9; k++) { dp[i][j]+=dp[i-1][k]; } } }}long long int DP(long long int N){ char num[20]; memset(num, 0, sizeof(num)); int size=0; long long int sum=0; while (N) { num[++size]=N%10; N/=10; } bool flag=0; for (int i=size; i>=1; i--) { if (flag) { sum+=num[i]*pow(10, i-1); continue; } for (int j=num[i]-1; j>=0; j--) sum+=dp[i][j]; if (num[i]==9 && num[i+1]==4) flag=1; } return sum;}int main(){ memset(dp, 0, sizeof(dp)); memset(dp, 0, sizeof(dp)); handle(); cin >> T; while (T--) { scanf("%lld",&N); N=DP(N+1); printf("%lld\n",N); } return 0;}
- HDU 3555 Bomb (数位DP)
- hdu 3555 - Bomb [数位dp]
- hdu 3555 Bomb【数位DP】
- HDU 3555 Bomb (数位DP)
- hdu 3555 Bomb 数位DP
- HDU 3555 Bomb (数位DP)
- hdu 3555 Bomb 数位dp
- [HDU 3555]Bomb[数位DP]
- HDU 3555 Bomb 数位DP
- hdu 3555 Bomb 数位dp
- HDU --3555--Bomb--数位DP
- hdu 3555 Bomb (数位DP)
- 【数位DP】【HDU 3555】Bomb
- hdu 3555 Bomb(数位DP)
- HDU 3555 Bomb(数位dp)
- 数位dp HDU 3555 Bomb
- HDU-3555 Bomb 数位DP
- HDU 3555 Bomb(数位DP)
- Yii2.0 search 搜索类
- AddressBookUI
- hdu--3790
- 爱生活
- java IO 字节编码
- 数位DP-HDU-3555-Bomb
- c语言中认识指针
- 使用WPR和WPA分析线程等待(分析锁的影响)
- 1231 - Coin Change (I) (简单DP)
- 3-8译码器-20151028
- 安装linux系统之RHEL7或CENTOS7系统(完整版)
- C/C++函数参数读取顺序
- java基础之static关键字(1)
- 算法竞赛入门-枚举-7.3.3-二进制法