Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 1604 Accepted Submission(s): 592
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?
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.
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 15HintFrom 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
Recommend
zhouzeyong
顺便写道数位dp的题,直接dfs下去就可以了,没什么说的。
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- using namespace std;
- int dig[20];
- long long dp[20][2][12];
- long long F(int pos,bool have,int last,bool inf)
- {
- int i;
- if (pos==-1) return have;
- if (!inf && dp[pos][have][last]!=-1) return dp[pos][have][last];
- int end=inf?dig[pos]:9;
- long long ans=0;
- for (i=0;i<=end;i++)
- {
- if (last==4 && i==9) ans+=F(pos-1,true,i,inf && (i==end));
- else ans+=F(pos-1,have,i,inf && (i==end));
- }
- if (!inf)
- {
- dp[pos][have][last]=ans;
- }
- return ans;
- }
- long long Cal(long long t)
- {
- int i,j,pos=0;
- while(t)
- {
- dig[pos++]=t%10;
- t/=10;
- }
- return F(pos-1,0,0,1);
- }
- int main()
- {
- int i,j,T;
- __int64 n;
- scanf("%d",&T);
- while(T--)
- {
- memset(dp,-1,sizeof(dp));
- scanf("%I64d",&n);
- printf("%I64d\n",Cal(n));
- }
- return 0;
- }
做的第一道数位DP啊!开始在找规律,搜索,做了很久终于找到了规律,上网一查发现原来这样的叫数位DP。。
找到的规律就是这个样子了。有了规律就很好做了。dp[i][0]=dp[i-1][0]*10-dp[i-1][1];是因为要减去49XXX的情况。
- //Time:15MS
- //Memory:488K
- #include<string.h>
- #include<stdio.h>
- long long dp[20][3];
- int num[20];
- int main()
- {
- memset(dp,0,sizeof(dp));
- dp[0][0] = 1;
- for(int i = 1;i<= 20;i++){
- dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; //dp[i][0] 表示i位数字中不含49的数字的个数
- dp[i][1]=dp[i-1][0]; //dp[i][1] 表示i位数字中以9开头的数字的个数
- dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//dp[i][2] 表示i位数字中含有49的数字的个数
- }
- int t;
- scanf("%d",&t);
- while(t--)
- {
- int len = 0,last = 0;
- long long ans = 0;
- long long n = 0;
- scanf("%I64d",&n);
- n++;
- memset(num,0,sizeof(num));
- while(n){
- num[++len]=n%10;
- n/=10;
- }
- bool flag=false;
- for(int i=len;i>=1;i--)
- {
- ans+=dp[i-1][2]*num[i];
- if(flag)
- {
- ans+=dp[i-1][0]*num[i];
- }
- if(!flag && num[i]>4)
- {
- ans+=dp[i-1][1];
- }
- if(last==4 && num[i]==9)
- {
- flag=true;
- }
- last=num[i];
- }
- printf("%I64d\n",ans);
- }
- }
转载请注明出处:http://blog.youkuaiyun.com/a1dark
分析:初学数位DP完全搞不懂、很多时候都是自己花大量时间去找规律、记得上次网络赛有道数位DP、硬是找规律给A了、那时候完全不知数位DP为何物、不过还是有很多时候要用数位DP、比如当一个数字超过了数组承受的极限、不能再打表AC、先看这道题、首先划分状态、然后初始化、最后从高位向低位状态转移、代码含详解
- //dp[len][0]表示长度为len不含49的数量
- //dp[len][1]表示长度为len不含44但以9开头的数字的数量
- //dp[len][2]表示长度为len含有49的数量
- #include<stdio.h>
- #include<string.h>
- __int64 dp[20][3];
- int num[20];
- int main(){
- dp[0][0]=1;
- for(int i=1;i<=20;i++){
- dp[i][0]=dp[i-1][0]*10-dp[i-1][1];//要减去9开头的数
- dp[i][1]=dp[i-1][0];//在不含49的数量中加9在开头
- dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//以前含49、这一位有10种选择+以前只含9这一位可以是4
- }
- int t;
- scanf("%d",&t);
- while(t--){
- int len=1,last=0;
- __int64 ans=0,n=0;
- scanf("%I64d",&n);
- memset(num,0,sizeof(num));
- n++;
- while(n>0){//用num数组来记录每一位的数字、为下面递推做准备
- num[len]=n%10;
- n/=10;
- len++;
- }
- int flag=0;
- for(int i=len;i>=1;i--){//从高位往低位递推
- ans+=dp[i-1][2]*num[i];//如果后面含有49、那么这一位可以填1到(num[i]-1)
- if(flag==1)//如果前一位挨着49
- ans+=dp[i-1][0]*num[i];//那么加上这个是没问题的
- if(flag==0&&num[i]>4)//如果前一位没有挨着49、但是这一位比4大
- ans+=dp[i-1][1];//那么加上开头为9的是正确的、
- if(last==4&&num[i]==9)//判断当前位和上一位是否能组成49
- flag=1;
- last=num[i];//当前位转移为上一位
- }
- printf("%I64d\n",ans);
- }
- return 0;
- }