概述
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("%lldn",N);
}
return 0;
}
最后
以上就是整齐长颈鹿为你收集整理的数位DP-HDU-3555-Bomb的全部内容,希望文章能够帮你解决数位DP-HDU-3555-Bomb所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复