# 数位DP初步 bzoj1026 hdu2089 hdu3555

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

# 不要62

Problem Description

62315 73418 88914

Input

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数？

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

【输出样例一】
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  阅读(200)  评论(0编辑  收藏