其他分享
首页 > 其他分享> > [BZOJ]1026[SCOI2009]windy数

[BZOJ]1026[SCOI2009]windy数

作者:互联网

题目链接:[SCOI2009]windy数

 题意:

求[l,r]之间的有多少个数满足:不包含前导0,且相邻两位数字差大于等于2。

 

题解:  

第一次不看题解一遍通过数位dp祭(虽然以前做过这道题,但是已经忘了)。

数位dp一直是恶心我的难点,这道题刚好是一道很简单的的数位dp,于是想尝试一下。

数位dp肯定要记忆化搜索,其他的奇怪实现方法我觉得都没有记搜简单明了且方便实现。

dfs(i, f, lst, limit)

表示第i位,是否有前导0,前面一个数是多少,是否碰到上限的方案数。

 

于是枚举当前位置的数,需要考虑以下几种情况。

首先当现在枚举的数是0的时候,会出现传递前面前导0的作用,于是判断前导0。

然后如果当前顶到上界,需要考虑当前数字是否小于上界。

如果没顶到上界,则需要考虑当前数字跟上一位差值是多少。

 

记住每种情况都要分类是否前面为前导0,因为前导0跟第一个数字不用比较差值大于等于2。

 

#include <bits/stdc++.h>
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read() {
    char c; int num, f = 1;
    while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
    while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
    return f * num;
}
int dp[20][2][20][2];
int a[1009], cnt;
int dfs(int res, int f, int lst, int limit) {
    if(dp[res][f][lst][limit] != -1) return dp[res][f][lst][limit];
    dp[res][f][lst][limit] = 0;
    if(res == 0) return dp[res][f][lst][limit] = 1;
    for(int i = 0; i < 10; i++) {
        if(i == 0) {
            if(f == 1) dp[res][f][lst][limit] += dfs(res - 1, 1, 0, 0);
            else if(lst >= 2) dp[res][f][lst][limit] += dfs(res - 1, 0, 0, limit && (i == a[res]));
        } else if(limit && i <= a[res]) {
            if(f == 1) dp[res][f][lst][limit] += dfs(res - 1, 0, i, limit && (i == a[res]));
            else if(abs(i - lst) >= 2) dp[res][f][lst][limit] += dfs(res - 1, 0, i, limit && (i == a[res]));
        } else if(!limit) {
            if(f == 1 || abs(i - lst) >= 2)
                dp[res][f][lst][limit] += dfs(res - 1, 0, i, 0);
        }
    }
    return dp[res][f][lst][limit];
}
signed main()
{

    int l = read() - 1, r = read();
    int cntl, cntr;
    cnt = 0;
    while(r > 0) a[++cnt] = r % 10, r /= 10;
    memset(dp, -1, sizeof(dp));
    cntr = dfs(cnt, 1, 0, 1);
    cnt = 0;
    while(l > 0) a[++cnt] = l % 10, l /= 10;
    memset(dp, -1, sizeof(dp));
    cntl = dfs(cnt, 1, 0, 1);
    printf("%d\n", cntr - cntl);
    return 0;
}
View Code

 

标签:cnt,1026,res,lst,dfs,windy,limit,SCOI2009,dp
来源: https://www.cnblogs.com/onglublog/p/14728498.html