hdu4722(数位dp)
Good Numbers
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3971 Accepted Submission(s): 1269
Problem Description
If we sum up every digit of a number and the result can be exactly divided by 10, we say this number is a good number.
You are required to count the number of good numbers in the range from A to B, inclusive.
You are required to count the number of good numbers in the range from A to B, inclusive.
Input
The first line has a number T (T <= 10000) , indicating the number of test cases.
Each test case comes with a single line with two numbers A and B (0 <= A <= B <= 1018).
Each test case comes with a single line with two numbers A and B (0 <= A <= B <= 1018).
Output
For test case X, output "Case #X: " first, then output the number of good numbers in a single line.
Sample Input
2 1 10 1 20
Sample Output
Case #1: 0 Case #2: 1HintThe answer maybe very large, we recommend you to use long long instead of int.
题意:求区间[l,r]之间的数的位数和能整除10的数的个数。
思路:数位dp。dp[i][j]表示i位数其中对10取余为j的数的个数。
数位dp有两大阵营,递推派与递归派,各有其长,递归的更容易敲,递推的更容易想。不过递推的要想完全理解真的挺难,所以还是回归递归吧!
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<stack> using namespace std; typedef long long ll; ll dp[20][10];///dp[i][j]表示i位对10取余为j的有多少个数 int digit[20]; ll dfs(int pos,int st,bool limit) { if(pos==0)return st==0; if(!limit&&dp[pos][st]!=-1)return dp[pos][st]; ll ans=0; int end=limit?digit[pos]:9; for(int i=0; i<=end; i++) ans+=dfs(pos-1,(i+st)%10,limit&&(i==end)); if(!limit) dp[pos][st]=ans; return ans; } ll get(ll x) { int bj=0; while(x) digit[++bj]=x%10,x/=10; return dfs(bj,0,1); } int main() { int t,o=1; memset(dp,-1,sizeof(dp)); scanf("%d",&t); while(t--) { ll l,r; scanf("%I64d%I64d",&l,&r); printf("Case #%d: %I64d\n",o++,get(r)-get(l-1)); } return 0; }
自己以前写的递推:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<stack> using namespace std; typedef long long ll; ll dp[20][20]; void init() { for(int i=0; i<10; i++) dp[1][i]=1; for(int i=2; i<=20; i++) for(int j=0; j<10; j++) for(int k=0; k<10; k++) dp[i][(j+k)%10]+=dp[i-1][k]; } ll get(ll x) { if(x==0)return 1; int digit[20],bj=0,sum=0; while(x) digit[++bj]=x%10,x/=10; ll ans=0; for(int i=bj; i>0; i--) { if(i>1) for(int j=0; j<digit[i]; j++) ans+=dp[i-1][(sum+j)%10]; else for(int j=0; j<=digit[i]; j++) if((sum+j)%10==0) ans++; sum=(sum+digit[i])%10; } return ans; } int main() { init(); int t,o=1; scanf("%d",&t); while(t--) { ll a,b; scanf("%I64d%I64d",&a,&b); printf("Case #%d: %I64d\n",o++,get(b)-get(a-1)); } return 0; }
持续更新博客地址:
blog.csdn.net/martinue