zoukankan      html  css  js  c++  java
  • 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
    ", 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)
    ", 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)
    ", 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)
    ", 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
    ", ans );
    74 }
    View Code

        

  • 相关阅读:
    WINCE创建快捷方式
    Android初级开发第四讲系统中一些属性的区别
    Android初级开发第六讲Activity的布局
    Android初级开发第三讲项目中控件的学习
    物联网产业链及市场分
    读《浪潮之巅》有感
    Hello China V1.75成功运行于Lenovo超级本上
    Android初级开发第七讲特效和数据传递处理
    Android中级第二讲制作搜索页面,使用TextWatcher
    电信运营商物联网实践建议
  • 原文地址:https://www.cnblogs.com/idy002/p/4354738.html
Copyright © 2011-2022 走看看