zoukankan      html  css  js  c++  java
  • 数位dp合集w

    【BZOJ1026】【SCOI2009】windy数

    传送门~:http://www.lydsy.com/JudgeOnline/problem.php?id=1026

    数位dp傻题QaQ

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 using namespace std;
     6 int f[15][15], A, B, da[15];
     7 void get_ready(){
     8     for (int i = 0; i <= 9; i++) f[1][i] = 1; 
     9     for (int i = 2; i <= 10; i++){
    10         for (int j = 0; j <= 9; j++) {
    11             for (int k = 0; k <= 9; k++) {
    12                 if (abs(j-k) >= 2)    f[i][j] += f[i-1][k];
    13             }
    14         }
    15     }
    16 }
    17 
    18 int calc(int a){
    19     if (a == 0) return 0;
    20     int ret = 0, len = 0;
    21     do{
    22         da[++len] = a % 10;
    23         a /= 10;
    24     }while(a);
    25     for (int i = 1; i < len; i++)
    26         for (int j = 1; j <= 9; j++)
    27             ret += f[i][j];
    28     for (int i = 1; i < da[len]; i++) ret += f[len][i];
    29     for (int i = len-1; i > 0; i--) {
    30         for (int j = 0; j < da[i]; j++)
    31             if (abs(j-da[i+1]) >= 2) ret += f[i][j];
    32         if (abs(da[i]-da[i+1]) < 2) break;
    33     }
    34     return ret;
    35 }
    36 
    37 int main(){
    38     freopen("bzoj1026.in", "r", stdin);
    39     freopen("bzoj1026.out", "w", stdout);
    40     get_ready();
    41     scanf("%d%d", &A, &B);
    42     printf("%d
    ", calc(B+1) - calc(A));
    43     return 0;
    44 }
    _(:з」∠)_

    【HDU3652】B-number

    传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12990

    题意:问1~n中包含"13"序列且能被13整除的数有多少个。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 int n, da[30];
     8 int f[15][3][15], vis[15][3][15];
     9 
    10 int dp(int len, int up, int type, int mod){
    11     if (!len) return (!mod && type == 2);
    12     if (!up && vis[len][type][mod]) return f[len][type][mod];
    13     int ret = 0, top = up ? da[len] : 9;
    14     for (int i = 0; i <= top; i++){
    15         int x = type;
    16         if (type == 0 && i == 1) x = 1;
    17         if (i != 1 && type == 1) x = 0;
    18         if (type == 1 && i == 3) x = 2;
    19         ret += dp(len-1, up&&(i==top), x, (mod*10 + i)%13);
    20     }
    21     if (!up){
    22         vis[len][type][mod] = 1;
    23         f[len][type][mod] = ret;
    24     }
    25     return ret;
    26 }
    27 
    28 int calc(int a){
    29     int len = 0;
    30     while (a){
    31         da[++len] = a % 10;
    32         a /= 10;
    33     }
    34     return dp(len, 1, 0, 0);
    35 }
    36 
    37 int main(){
    38     freopen("hdu3652.in", "r", stdin);
    39     freopen("hdu3652.out", "w", stdout);
    40     int l = 0;
    41     while (~scanf("%d", &n)){
    42         memset(f, 0, sizeof(f));
    43         memset(vis, 0, sizeof(vis));
    44         printf("%d
    ", calc(n));
    45     }
    46 //    for (int i = 1; i <= 10010; i++)
    47 //        cout<<i<<" "<<calc(i)<<" "<<i%p<<endl;
    48     return 0;
    49 }
    View Code

    【HDU3709】Balanced Number

    传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=41280

    题意:题目先给出平衡数的概念:数n以数n中的某个位为支点,每个位上的数权值为(数字xi*(posi - 支点的posi)),如果数n里有一个支点使得所有数权值之和为0那么她就是平衡数。比如4139,以3为支点,左边 = 4 * (4 - 2) + 1 * (3 - 2) = 9,右边 = 9 * (1 - 2) = -9,左边加右边为0,所以4139是平衡数。现在给出一个区间[l,r],问区间内平衡数有多少个?

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 #define LL long long
     6 using namespace std;
     7 int da[20];
     8 LL l, r;
     9 LL f[20][20][2100];
    10 
    11 LL dp(int len, int pos, int up, int l){
    12     if (!len || l < 0) return l == 0;
    13     if (!up && f[len][pos][l] != -1) return f[len][pos][l];
    14     LL ret = 0ll;
    15     int top = up ? da[len] : 9;
    16     for (int i = 0; i <= top; i++) {
    17         ret += dp(len-1, pos, up&&(i==top), l+(len-pos)*i);
    18     }
    19     if (!up) f[len][pos][l] = ret;
    20     return ret;
    21 }
    22 
    23 LL calc(LL a){
    24     int len = 0;
    25     LL ret = 0ll;
    26     while(a){
    27         da[++len] = (int) (a % 10);
    28         a /= 10ll;
    29     }
    30     for (int i = 1; i <= len; i++) {
    31         ret += dp(len, i, 1, 0);
    32     }
    33     return ret-(LL)len+1;
    34 }
    35 
    36 int main(){
    37     freopen("hdu3709.in", "r", stdin);
    38     freopen("hdu3709.out", "w", stdout);
    39     int T;
    40     scanf("%d", &T);
    41     memset(f, -1, sizeof(f));
    42     while (T--){
    43         scanf("%lld%lld", &l, &r);
    44         printf("%lld
    ", calc(r) - calc(l-1));
    45     }
    46     return 0;
    47 }
    View Code

    【HDU3886】 Final Kichiku “Lanlanshu”

    传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=21534

    题意:A,B之间有多少个数,满足给定字符串的趋势,字符串由“/”“-”“”这3个字符构成,分别表示上升,不变和下降。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 using namespace std;
     6 const int p = 1e8;
     7 char ca[110], cb[110], c[110];
     8 int lenK, lenC;
     9 int da[110], K[110];
    10 int f[110][110][10];
    11 
    12 bool getk(char s, int i, int las){
    13     if (s == '-') return i == las;
    14     if (s == '/') return i > las;
    15     if (s == '\') return i < las;
    16     return 0;
    17 }
    18 
    19 int dp(int len, int up, int zero, int k, int las){
    20     //cout<<k<<endl;
    21     if (!len) return k == lenK;
    22     if (!up && !zero && f[len][k][las]!=-1) return f[len][k][las];
    23     int ret = 0, top = up ? da[len] : 9;
    24     for (int i = 0; i <= top; i++){
    25         if (zero) {
    26             if (!i) ret += dp(len-1, up&&(i==top), 1, 0, -1), ret %= p;
    27             else ret += dp(len-1, up&&(i==top), 0, 0, i), ret %= p;
    28         }
    29         else {
    30             if(getk(c[k], i, las) && k < lenK)
    31                 ret += dp(len-1, up&&(i==top), 0, k+1, i), ret %= p;
    32             else if((k > 0 && getk(c[k-1], i, las)))
    33                 ret += dp(len-1, up&&(i==top), 0, k, i), ret %= p;    
    34         }
    35     }
    36     if (!up && !zero) f[len][k][las] = ret;
    37     return ret;
    38 }
    39 
    40 int calc(char *ch, int x){
    41     int len = strlen(ch);
    42     for (int i = 0; i < len; i++) da[len-i] = ch[i]-'0';
    43     while (!da[len] && len > 1) len--;
    44     if (len == 1 && !da[len]) return 0;
    45     if (x) {
    46         da[1]--;
    47         for (int i = 1; i < len; i++)
    48             if (da[i] < 0) da[i] += 10, da[i+1]--;
    49         while (!da[len] && len > 1) len--;
    50     }
    51     if (len == 1 && !da[len]) return 0;
    52     //cout<<dp(len, 1, 1, 1, -2)<<endl;
    53     return dp(len, 1, 1, 0, -1);
    54 }
    55 
    56 int main(){
    57     freopen("hdu3886.in", "r", stdin);
    58     freopen("hdu3886.out", "w", stdout);
    59     while (~scanf("%s%s%s",c, ca, cb)){
    60         memset(f, -1, sizeof(f));
    61         lenK = strlen(c);
    62         printf("%08d
    ",(calc(cb, 0) - calc(ca, 1) + p) % p);
    63     }
    64     return 0;
    65 }
    View Code

    【HDU3943】K-th nya number

    传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22331

    题意:求出区间 (P,Q] 中找到第K个满足条件的数,条件是该数包含X个4和Y个7。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <iostream>
     4 #define MaxN 110
     5 #define LL long long
     6 using namespace std;
     7 LL p, q, ls;
     8 LL f[30][2][21][21];
     9 int da[30], x, y;
    10 int vis[30][2][21][21];
    11 
    12 LL dp(int len, int up, int zero, int a, int b){
    13     if (!len) return (!a && !b);
    14     if (a < 0 || b < 0) return 0ll;
    15     if (!up && vis[len][zero][a][b]) return f[len][zero][a][b];
    16     LL ret = 0ll;
    17     int top = up ? da[len] : 9;
    18     if (zero) ret = dp(len - 1, 0, 1, a, b);
    19     for (int i = zero; i <= top; i++){
    20         ret += dp(len-1, up&&(i==top), 0, a-(i==4), b-(i==7));
    21     }
    22     if (!up){
    23         f[len][zero][a][b] = ret;
    24         vis[len][zero][a][b] = 1;
    25     }
    26     return ret;
    27 }
    28 
    29 LL calc(LL a){
    30     int len = 0;
    31     while (a){
    32         da[++len] = (int) (a % 10);
    33         a /= 10ll;
    34     }
    35     return dp(len, 1, 1, x, y);
    36 }
    37 
    38 void Solve(LL k){
    39     LL l = p, r = q, mid;
    40     while (l + 1 < r){
    41         mid = (l + r) / 2;
    42         if ((calc(mid)-ls) < k) l = mid;
    43         else r = mid;    
    44     }
    45     if ((calc(r)-ls) == k) printf("%lld
    ", r);
    46     else printf("Nya!
    ");
    47 }
    48 
    49 int main(){
    50     freopen("hdu3943.in", "r", stdin);
    51     freopen("hdu3943.out", "w", stdout);
    52     int T, query, l = 0;
    53     LL k;
    54     scanf("%d", &T);
    55     while (T--){
    56         scanf("%lld%lld%d%d", &p, &q, &x, &y);
    57         scanf("%d", &query);
    58         ls = calc(p);
    59         printf("Case #%d:
    ", ++l);
    60         for (int i = 1; i <= query; i++) {
    61             scanf("%lld", &k);
    62             Solve(k);
    63         }
    64     }
    65     return 0;
    66 }
    View Code

    【HDU4352】XHXJ's LIS

    传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30872

    题意:问L到R,各位数字组成的最长上升子序列的长度为K的数的个数。

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 #define LL long long
     6 using namespace std;
     7 int T, k;
     8 int da[30];
     9 LL f[30][1<<10][11];
    10 LL l, r;
    11 
    12 int gets(int s, int x){
    13     for (int i = x; i <= 9; i++){
    14         if (s & (1<<i)) return (s^(1<<i)) | (1<<x);
    15     }
    16     return s|(1<<x);
    17 }
    18 
    19 int getk(int x){
    20     int ret = 0;
    21     while(x){
    22         ret += x & 1;
    23         x >>= 1;
    24     }
    25     return ret;
    26 }
    27 
    28 LL dp(int len, int up, int zero, int s){
    29     if (!len) return getk(s) == k;
    30     if (!up && f[len][s][k] != -1) return f[len][s][k];
    31     LL ret = 0ll;
    32     int top = up ? da[len] : 9;
    33     if (zero) ret = dp(len-1, 0, 1, 0);
    34     for (int i = zero; i <= top; i++){
    35         ret += dp(len-1, up&&(i==top), 0, gets(s, i));
    36     }
    37     if (!up) f[len][s][k] = ret;
    38     return ret;
    39 }
    40 
    41 LL calc(LL a){
    42     int len = 0;
    43     while (a){
    44         da[++len] = (int) (a % 10);
    45         a /= 10ll;
    46     }
    47     return dp(len, 1, 1, 0);
    48 }
    49 
    50 int main(){
    51     freopen("hdu4352.in", "r", stdin);
    52     freopen("hdu4352.out", "w", stdout);
    53     scanf("%d", &T);
    54     memset(f, -1, sizeof(f));
    55     for (int i = 1; i <= T; i++){
    56         scanf("%lld%lld%d", &l, &r, &k);
    57         printf("Case #%d: %lld
    ", i, calc(r)-calc(l-1));
    58     }
    59     return 0;
    60 }
    View Code

    【SCOI2014】【BZOJ3598】方伯伯的商场之旅

    看这里看这里whttp://www.cnblogs.com/Lukaluka/p/5206022.html

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 #define LL long long
     6 using namespace std;
     7 const int MaxN = 65;
     8 int u[MaxN], d[MaxN], LEN;
     9 LL l, r, k;
    10 LL f[MaxN][2][2], g[MaxN][1600], ans[2333], sum[MaxN][2][2];
    11 
    12 LL dp(int len, int up, int down){
    13     if (!len) { sum[len][up][down] = 1; return 0; }
    14     if (f[len][up][down]!= -1) return f[len][up][down];
    15     LL ret = 0ll, num = 0ll;
    16     int top = up ? u[len] : (int)k-1, bot = down ? d[len] : 0;
    17     for (int i = bot; i <= top; i++){
    18         int p1 = (i==top)&&up, p2 = i==bot&&down;
    19         ret += dp(len-1, p1, p2) + i*(len-1)*sum[len-1][p1][p2];
    20         num += sum[len-1][p1][p2];
    21     }
    22     f[len][up][down] = ret, sum[len][up][down] = num;
    23     return ret;
    24 }
    25 
    26 LL calc(LL x, LL y){
    27     int len = 0, len2 = 0;
    28     while(x){
    29         u[++len] = (int) (x%k);
    30         x /= k;
    31     }
    32     while(y){
    33         d[++len2] = (int) (y%k);
    34         y /= k;
    35     }
    36     LEN = len;
    37     return dp(len, 1, 1);
    38 }
    39 
    40 LL dfs(int len, int up, int down, int p, int s){
    41     if (!len) return (LL)s;
    42     if (!up && !down && g[len][s] != -1) return g[len][s];
    43     LL ret = 0;
    44     int top = up ? u[len] :(int)k-1, bot = down ? d[len] : 0;
    45     for (int i = bot; i <= top; i++){
    46         int x = (len >= p ? 1 : -1), c = i==top&&up, d = i==bot&&down;
    47         x = x*i + s;
    48         if (x < 0) break;
    49         ret += dfs(len-1, c, d, p, x);
    50     }
    51     if (!up && !down) g[len][s] = ret;
    52     return ret;
    53 }
    54 
    55 void Solve(){
    56     memset(f, -1ll, sizeof(f));
    57     LL ret = calc(r, l);
    58     //cout<<ret<<endl;
    59     LL dec = 0ll;
    60     for (int i = 2; i <= LEN; i++){
    61         memset(g, -1ll, sizeof(g)), dec += dfs(LEN, 1, 1, i, 0);
    62     }
    63     cout<<ret - dec;
    64 }
    65 
    66 int main(){
    67     cin>>l>>r>>k;
    68     Solve();
    69     return 0;
    70 }
    View Code

    啊TuT待更

  • 相关阅读:
    Linux下MySQL主从同步配置
    Tortoisegit图文使用教程
    C语言I博客作业06
    第十周助教总结
    C语言I博客作业04
    C语言I博客作业02
    第十一周助教总结
    第十二周助教总结
    第九周助教总结
    C语言I博客作业02
  • 原文地址:https://www.cnblogs.com/Lukaluka/p/5190624.html
Copyright © 2011-2022 走看看