数位DP初步 bzoj1026 hdu2089 hdu3555

为了搞SCOI的几道题先做水数位。
之前听过课,半懂不懂吧,现在清楚了些。

这类题一般满足区间减法,即只需要我们求出(1,n)即可,然后打表也是为了sovle(DataType)服务。
先想好怎么计算,再去想怎么打表。
计算是一般存在这样的问题,就是比如n=abcdef,当a=6时,6开头的不能全算,那就只能先算1~5,然后理解为把6摆好,算下一位,这样我们发现,这个函数是没有包含n这个数的,所以调用是要调用sovle(n+1)

不要62

Problem Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
 

 

Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
 

 

Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
 

 

Sample Input
1 100 0 0
 

 

Sample Output
80
 
 
 
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 int dp[10][3];//dp[i]表示第i位,dp[i][0]吉利的,dp[i][1]第一位为2的吉利的,dp[i][2]为不吉利的 
 9 void table_maker() {
10     dp[0][0]=1;
11     for(int i=1;i<=6;i++){
12         dp[i][0]=dp[i-1][0]*9-dp[i-1][1];
13         dp[i][1]=dp[i-1][0];
14         dp[i][2]=dp[i-1][2]*10+dp[i-1][1]+dp[i-1][0];
15     }
16 }
17 int calc(int n) {
18     int a[10]={0},ans=0,flag=0,tmp=n*10,len=0;
19     for(;tmp/=10;)a[++len]=tmp%10;
20     for(int i=len;i>=1;i--){
21         ans+=a[i]*dp[i-1][2];
22         if(flag)ans+=a[i]*dp[i-1][0];
23         else{
24             if(a[i]>4)ans+=dp[i-1][0];
25             if(a[i]>6)ans+=dp[i-1][1];
26             if(a[i+1]==6&&a[i]>2)ans+=dp[i][1];
27             if(a[i]==4||(a[i+1]==6&&a[i]==2))flag=1;
28         }
29     }
30     return n-ans;
31 }
32 
33 int main() {
34     freopen("in.txt","r",stdin);
35 //    freopen("out.txt","w",stdout);
36     
37     table_maker();
38     for(int l,r;~scanf("%d%d",&l,&r)&&(l||r);)printf("%d\n",calc(r+1)-calc(l));
39     return 0;
40 }
 

Bomb(要49)

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.
 
 
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 using namespace std;
 7 #ifndef UNIX
 8     #define LL "%I64d"
 9 #else
10     #define LL "%lld"
11 #endif
12 const int N=20;
13 typedef long long ll;
14 ll dp[N][3],x;// dp[][0]不含49 dp[][1]不含49首位为9,dp[][2]含49
15 void mk_tb() {
16     dp[0][0]=1;
17     for(int i=1; i<N; i++) {
18         dp[i][0]=dp[i-1][0]*10-dp[i-1][1];
19         dp[i][1]=dp[i-1][0];
20         dp[i][2]=dp[i-1][2]*10+dp[i-1][1];
21     }
22 }
23 ll f(ll n) {
24     ll tmp=n,ans=0;
25     int a[N]={0},flag=0;
26     for(*a=0; tmp; tmp/=10)a[++*a]=tmp%10;
27     for(int i=*a; i; i--) {
28         ans+=a[i]*dp[i-1][2];
29         if(flag)ans+=a[i]*dp[i-1][0];
30         else {
31             if(a[i]>4)ans+=dp[i-1][1];
32             if(a[i+1]==4 && a[i]==9)flag=1;
33         }
34     }
35     return ans;
36 }
37 int main() {
38     freopen("in.txt","r",stdin);
39     freopen("","w",stdout);
40     mk_tb();int n;
41     for(scanf("%d",&n);n--;){
42         scanf(LL,&x);
43         printf(LL"\n",f(x+1));
44     }
45     
46     return 0;
47 }

1026: [SCOI2009]windy数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3075  Solved: 1376
[Submit][Status]

Description

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?

Input

包含两个整数,A B。

Output

一个整数。

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

HINT

 

【数据规模和约定】

100%的数据,满足 1 <= A <= B <= 2000000000 。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cstdio>
 6 #include<numeric>
 7 using namespace std;
 8 typedef int ll;
 9 const int N=10;
10 ll dp[N+1][10];//dp[i][j]表示第i位为j的windy数的个数
11 void mk_tb(){
12     for(int i=0;i<=9;i++)dp[1][i]=1;
13     for(int i=2;i<=N;i++){
14         for(int j=0;j<=9;j++){
15             for(int k=0;k<=9;k++){
16                 if(abs(j-k)>=2){
17                     dp[i][j]+=dp[i-1][k];
18                 }
19             }
20         }
21     }
22 }
23 ll f(ll n){
24     int ans=0,a[N+1]={0},len=0;
25     for(int tmp=n;tmp;tmp/=10)a[++len]=tmp%10;
26     for(int i=1;i<len;i++)ans+=accumulate(dp[i]+1,dp[i]+N,0);
27     for(int i=1;i<a[len];i++)ans+=dp[len][i];
28     for(int i=len;--i;){
29         for(int j=0;j<a[i];j++)if(abs(j-a[i+1])>=2)ans+=dp[i][j];
30         if(abs(a[i]-a[i+1])<2)break;
31     }
32     return ans;
33 }
34 int main() {
35     freopen("in.txt","r",stdin);
36     freopen("","w",stdout);
37     
38     mk_tb();
39     int a,b;
40     scanf("%d%d",&a,&b);
41     printf("%d\n",f(b+1)-f(a));
42     
43     return 0;
44 }

 

 
posted @ 2015-02-21 20:12  Showson  阅读(...)  评论(... 编辑 收藏