2016弱校联盟十一专场10.5 I Increasing or Decreasing(数位dp)

来源:互联网 发布:微信淘客助手群发软件 编辑:程序博客网 时间:2024/05/16 13:50

题目分析

这道题就是给你2个数,让你求在这2个数之间单调不减或者单调不增的数的个数,定义状态dp[i][j][k],i表示数的第I位,j表示当前位的前一位数字的多少,k则表达三种意思,k等于0时表示这个序列目前是单调不减的,k等于1表示是单调不增的,k等于2表示目前并没有确定这个序列到底是的单调性,也是就说前几位数是相等的,或者前几位数全为0.这样就可以通过dfs写出状态转移方程,注意不合理的状态可以直接晒掉,这样会减少时间同时比较好定义状态。看网上的代码写了140行,我的代码只有60行!!!!

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define LL long longconst int maxn = 25;LL bit[maxn], dp[maxn][15][5];LL dfs(int pos, int pre, int x, bool zero, bool limit){    if(pos < 1) return 1LL;    if(!limit && dp[pos][pre][x] != -1) return dp[pos][pre][x];    int len = limit?bit[pos]:9;    LL ret = 0;    for(int i = 0; i <= len; i++){        if(zero) ret += dfs(pos-1, i, x, zero&&i==0, limit&&i==len);        else{            int temp = x;            if(i < pre){                if(temp == 0) continue;                temp = 1;            }            else if(i > pre){                if(temp == 1) continue;                temp = 0;            }            ret += dfs(pos-1, i, temp, false, limit&&i==len);        }    }    if(!limit) dp[pos][pre][x] = ret;    return ret;}LL solve(LL n){    int len = 0;    while(n){        bit[++len] = n%10;        n /= 10;    }    return dfs(len, 0, 2, true, true);}int main(){    int T;    LL l, r;    scanf("%d", &T);    memset(dp, -1, sizeof(dp));    while(T--){        scanf("%lld%lld", &l, &r);        printf("%lld\n", solve(r) - solve(l-1));    }    return 0;}
0 0
原创粉丝点击