zoukankan      html  css  js  c++  java
  • 算法 数位DP(按位DP) hdoj 2089 hdoj 3555 uestc 1307 基础题 木

    按位dp:对于当前长度i是枚举该为的值(0~10),统计出区间内合法的数;

    下面是基础入门的3题;

    hdoj 2089 http://acm.hdu.edu.cn/showproblem.php?pid=2089 区间数内不包含4和62的数的个数

    View Code
     1  #include <iostream>
     2  #include <cstdio>
     3  #include <cstring>
     4  #include <algorithm>
     5  using namespace std;
     6 
     7 
     8  int num[10][10];
     9 
    10  // 预处理长度为i,取值为j时的合法元素个数;
    11  void Pre(){
    12      memset(num, 0, sizeof num);
    13      for ( int i=0; i<10; ++i )
    14         num[1][i] = 1;
    15      num[1][4] = 0;
    16      for ( int i=2; i<9; ++i )
    17      {
    18          for ( int j=0; j<10; ++j ) if(j ^ 4)
    19            for ( int k=0; k<10; ++k ) if(k ^ 4)
    20            {
    21                if(j==6 && k==2) continue; // 剔出非法的元素
    22                num[i][j] += num[i-1][k];
    23            }
    24      }
    25  };
    26 
    27  int count( int n ) {
    28       if(n <= 0) return 1;
    29       int a[12] = {0};
    30       while(n ) {
    31           a[++a[0] ] = n%10; n /= 10;
    32       }
    33       int ret = 0, last=-1;
    34       while(a[0] > 0) {
    35            int t = a[a[0] ];
    36            for ( int i=0; i<t; ++i ) {
    37                if(i == 4) continue;
    38                if(last==6 && i==2) continue;
    39                ret += num[a[0] ][i];
    40            }
    41            if(t^4 && a[0]==1 && !(last==6&&t==2)) ret += num[1][t];
    42           // 要考虑是否可以取最后一位
    43            if(t == 4)  break; // 后面的数据都是非法的
    44            if(last==6 && t==2) break; // 后面的数都是非法的
    45            last = t;
    46            --a[0];
    47       }
    48       //cout<<"  " << ret << endl;
    49       return ret;
    50  }
    51 
    52  int main(){
    53      Pre(); int L, R;
    54      while( ~scanf("%d%d", &L, &R), L||R ) {
    55            if(L > R) swap(L, R);
    56            int l = count(L-1);
    57            int r = count(R);
    58            printf("%d\n", r-l);
    59      }
    60  };

    hdoj http://acm.hdu.edu.cn/showproblem.php?pid=3555 统计区间出现字串49的个数

    View Code
     1 #include <iostream>
     2  #include <cstring>
     3  #include <cstdio>
     4  #include <algorithm>
     5  using namespace std;
     6 
     7  typedef __int64 ll;
     8 
     9  ll dp[30][10][2];
    10  // dp[i][j][0] 表示长度为i取值为j的不合法的元素个数;
    11  // dp[i][j][1] 表示长度为i取值为j的合法元素个数
    12 
    13  void Pre(){
    14      memset(dp, 0, sizeof dp);
    15      for ( int i=0; i<10; ++i ){
    16          dp[1][i][0] = 1;
    17      }
    18      for ( int i=2; i<30; ++i )
    19      {
    20          for ( int j=0; j<10; ++j )
    21          for ( int k=0; k<10; ++k ){
    22               if(!(j==4 && k==9) )
    23                dp[i][j][0] += dp[i-1][k][0];
    24               dp[i][j][1] += dp[i-1][k][1];
    25               if(k == 9 && j == 4)
    26                 dp[i][j][1] += dp[i-1][k][0];
    27          }
    28      }
    29      //for ( int i=0; i<10; ++i )
    30      // cout << dp[4][i][1] <<" "; puts("");
    31  };
    32 
    33  // 这里也要注意数据类型
    34  ll get(int *a, int l, int r){
    35     ll ret = 0;
    36     for(int i=l; i>=r; --i)
    37      ret = ret*10+a[i];
    38     return ret;
    39  }
    40 
    41  void count( ll n ){
    42      if(n < 49){
    43          puts("0");  return ;
    44      }
    45      int a[30]={0};
    46      while(n ) {
    47          a[++a[0] ] = n%10; n /= 10;
    48      }
    49      ll ret = 0;
    50      int last = -1;
    51      while(a[0] > 1) {
    52          int t = a[a[0] ];
    53          for ( int i=0; i<t; ++i )
    54            ret += dp[a[0] ][i][1];
    55          if(last==4 && t==9) { // 后面的数都是合法的,直接加上就可以了
    56               ret += get(a, a[0]-1, 1)+1;
    57               break;
    58          }
    59          if(a[0]==2 && a[a[0] ]==4 && a[a[0]-1 ]==9 ) ret++;
    60         // 考虑最后一位是否可取
    61          last = t;
    62          --a[0];
    63      }
    64      printf("%I64d\n", ret);
    65  };
    66 
    67  int main(){
    68      Pre();
    69      int T; ll n;  scanf("%d", &T);
    70      while( T-- ) {
    71          scanf("%I64d", &n);
    72          count(n);
    73      }
    74  }

    uestc http://acm.uestc.edu.cn/problem.php?pid=1307 统计区间内符合相邻数字差大于1的数;

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 
     9 ll dp[15][12];
    10 bool ok(int x, int y){
    11     return abs(x-y)>1;
    12 }
    13 
    14 void Pre(){
    15     memset(dp, 0, sizeof dp);
    16     for ( int i=0; i<10; ++i )
    17        dp[1][i] = 1;
    18     for ( int i=2; i<12; ++i ){
    19         for ( int j=0; j<10; ++j )
    20         {
    21             for ( int k=0; k<10; ++k )if(ok(j, k) ) {
    22                 dp[i][j] += dp[i-1][k];
    23             }
    24         }
    25     }
    26    /* for(int j=1; j<=3; puts(""), ++j )
    27     for ( int i=0; i<10; ++i )
    28       cout << dp[j][i] << " ";*/
    29 }
    30 
    31 ll count( ll x ) {
    32      int a[14]={0};
    33      while( x ) {
    34          a[++a[0] ] = x%10; x /= 10;
    35      }
    36      ll ret = 0;
    37      for ( int i=1; i<a[0]; ++i )
    38         for ( int j=1; j<10; ++j )
    39           ret += dp[i][j];
    40      int last = 20;
    41      while(a[0] > 0 ) {
    42          int t = a[a[0] ];
    43          for ( int i=(last==20?1:0); i<t; ++i )
    44            if(ok(i, last) ) ret += dp[a[0] ][i];
    45          //if(a[0]==1 && ok(t, last) ) ret += dp[1][t];
    46         // 这个不要啊,前导0会枚举到这个情况,开始就因为这里得不到正确结果的
    47          if(!ok(t, last) ) break;
    48          last = t;
    49          --a[0];
    50      }
    51     // cout << " " << ret << endl;
    52      return ret;
    53 };
    54 
    55 int main(){
    56     Pre();
    57     ll L, R;
    58     while( ~scanf("%lld%lld", &L, &R) ){
    59         ll l = count(L);
    60         ll r = count(R+1);
    61         printf("%lld\n", r-l);
    62     }
    63 };

    以上都是些基础题,还有很多这样的题;

    fzu 2070   http://acm.fzu.edu.cn/problem.php?pid=2070

    zoj 2599 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2599

    zoj 3162 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3162

    zoj 3494 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494

    codeforces 55D http://www.codeforces.com/problemset/problem/55/D

    codeforces 215E http://www.codeforces.com/problemset/problem/215/E

    codeforces 258B http://www.codeforces.com/problemset/problem/258/B

    。。。。。

  • 相关阅读:
    request实现登录
    python之对象
    python基础之迭代与解析
    python基础之函数
    linux expect命令使用入门
    Python socket
    1
    蓝牙
    SQL查询语句
    iOS常用小知识纪录
  • 原文地址:https://www.cnblogs.com/TengXunGuanFangBlog/p/digit_DP.html
Copyright © 2011-2022 走看看