bzoj 1026

 

很久以前做过的一道数位DP,现在用一种新的解决数位DP的比较一般的方法。

 

数位DP裸题是:求[L,R]有多少个数。

先转化成求[0,R]有多少个数,然后区间相减即可。

对于[0,R]中的所有数,用0补齐前面的空位,使得每个数的长度都为R的长度。

状态:

dp[pos][0]表示从最高位到pos位,没有顶上界的数的个数

dp[pos][1]表示从最高位到pos位,顶到上界的数的个数(好吧,这个问题中,它一定为1)

然后考虑转移,

dp[pos][0]->dp[pos-1][0](通过枚举pos-1位的数进行转移)

dp[pos][1]->dp[pos-1][0](通过枚举pos-1位,小于该位上界的数进行转移)

dp[pos][1]->dp[pos-1][1](只能在pos-1位填1)

顺推倒推都可以。

dp[1][0]+dp[1][1]就是答案。

 

对于其它的数位DP,都可以在这个DP上加上需要的状态维,然后解决其它问题。

上面的dp[pos][1]看似没有用(因为始终为1),但是实际上,我们是必须要它的,比如这道题。

我们设dp[pos][top][tail]表示:“比pos高的位,顶上界(top为1)或不顶上界(top为0),最后一位为tail的数的个数(并且要求这个数不为0)“

然后自己YY转移吧(这个不为0的要求和上一道题有点不同,具体看代码)。

 

 

新方法:

 1 /**************************************************************
 2     Problem: 1026
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:0 ms
 7     Memory:808 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cstring>
12 #define abs(a) ((a)>0?(a):-(a))
13  
14 typedef long long poi;
15  
16 poi lf, rg;
17 int aa[20], tot;
18 poi dp[20][2][10];
19  
20 poi calc( poi v ) {         //  v in [1,oo)
21     for( tot=0; v; v/=10 )
22         aa[++tot]=v%10;
23     memset( dp, 0, sizeof(dp) );
24     dp[tot][1][aa[tot]] = 1;
25     for( int i=1; i<aa[tot]; i++ )
26         dp[tot][0][i] = 1;
27     for( int i=tot; i>=2; i-- ) {
28         for( int c=0; c<=9; c++ )
29             for( int s=0; s<=9; s++ )
30                 if( abs(s-c)>=2 )
31                     dp[i-1][0][s] += dp[i][0][c];
32         for( int s=1; s<=9; s++ )
33             dp[i-1][0][s]++;
34         for( int s=0; s<aa[i-1]; s++ )
35             if( abs(s-aa[i])>=2 )
36                 dp[i-1][0][s] += dp[i][1][aa[i]];
37         dp[i-1][1][aa[i-1]] = dp[i][1][aa[i]] && abs(aa[i]-aa[i-1])>=2;
38     }
39     poi rt=dp[1][1][aa[1]];
40     for( int i=0; i<=9; i++ )
41         rt += dp[1][0][i];
42     return rt;
43 }
44 int main() {
45     scanf( "%lld%lld", &lf, &rg );
46     printf( "%lld\n", calc(rg)-(lf==1?0:calc(lf-1)) );
47 }
View Code

 

以前的:

 1 /**************************************************************
 2     Problem: 1026
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:0 ms
 7     Memory:804 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <algorithm>
12 using namespace std;
13  
14 struct Form {
15     int n;
16     int b[30];
17     int src;
18     Form( int a ) {
19         n = 0;
20         src = a;
21         if( a==0 ) {
22             n=1;
23             b[1] = 0;
24             return;
25         }
26         while( a ) {
27             b[++n] = a%10;
28             a/=10;
29         }
30     }
31 };
32 int dp[10][11];     // dp[0~9][0~10]
33  
34 void init() {
35     for( int h=0; h<=9; h++ )
36         dp[h][1] = 1;
37     for( int l=2; l<=10; l++ )
38         for( int h=0; h<=9; h++ )
39             for( int g=0; g<=9; g++ )
40                 if( abs(g-h)>=2 )
41                     dp[h][l] += dp[g][l-1];
42 }
43  
44 int calc( const Form &fm) { //  [0,fm.src)
45     int ans = fm.src!=0;    //  0
46     for( int l=1; l<fm.n; l++ )
47         for( int h=1; h<=9; h++ ) {
48             ans += dp[h][l];
49             //printf( "(h=%d,l=%d)\n", h, l );
50         }
51     for( int h=1; h<fm.b[fm.n]; h++ ) {
52         ans += dp[h][fm.n];
53         //printf( "(h=%d,l=%d)\n", h, fm.n );
54     }
55     for( int l=fm.n-1; l>=1; l-- ) {
56         for( int h=0; h<fm.b[l]; h++ )
57             if( abs(h-fm.b[l+1])>=2 ) {
58                 ans += dp[h][l];
59                 //printf( "(h=%d,l=%d)\n", h, l );
60             }
61         if( abs(fm.b[l]-fm.b[l+1])<2 ) break;
62     }
63     return ans;
64 }
65  
66 int main() {
67 //  freopen( "windy.in", "r", stdin );
68 //  freopen( "windy.out", "w", stdout );
69     int A, B, ans;
70     init();
71     scanf( "%d%d", &A, &B );
72     ans = calc(Form(B+1))-calc(Form(A));
73     printf( "%d\n", ans );
74 }
View Code

 

 

 

 

 

    

 

posted @ 2015-03-20 22:13  idy002  阅读(255)  评论(0编辑  收藏  举报