BZOJ 1026 [SCOI2009]windy数【数位DP】

题目链接:

http://www.lydsy.com/JudgeOnline/problem.php?id=1026

题意:

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

分析:

比较基础的数位dp,
dp[i][j][k][m] ,其中 k 标记是否与原数相等,m标记是否全为0,因为如果前面全为0的话,那么这一位可以放任何数。表示进行到第 i 位,数字为j的数一共有多少种,两个数做个差即可。

代码:

/*************************************************************************
    > File Name: 1026.cpp
    > Author: jiangyuzhu
    > Mail: 834138558@qq.com 
    > Created Time: 2016/7/18 20:52:36
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 10 + 5;
int dp[maxn][maxn][2][2];
char s[maxn];
int a[maxn];
int len;
int solve(char *s)
{
    len = strlen(s);
    for(int i = 0; i < len; i++){
        a[i] = s[i] - '0';
    }
    for(int i = 1; i < a[0]; i++){
        dp[0][i][1][1] = 1;
    }
    dp[0][a[0]][0][1] = 1;
    dp[0][0][1][0] = 1;// 全为0
    for(int i = 1; i < len; i++){
        if(abs(a[i] - a[i - 1]) >= 2) dp[i][a[i]][0][1] = dp[i - 1][a[i - 1]][0][1];
        for(int j = 0; j < 10; j++){
            for(int k = 0; k < 10; k++){    
                if(k == 0){
                    if(j == 0) dp[i][j][1][0] += dp[i - 1][k][1][0];
                    else dp[i][j][1][1] += dp[i - 1][k][1][0];
                }
                if(abs(j - k) >= 2)  dp[i][j][1][1] += dp[i - 1][k][1][1];
            }
            if(j < a[i] && abs(j - a[i - 1]) >= 2)
                dp[i][j][1][1] += dp[i - 1][a[i - 1]][0][1];
        }
    }
    int ans = 0;
    for(int i = 0; i < 10; i++){
        ans += dp[len - 1][i][1][1];
    }
    return ans;
}
int main (void)
{
    scanf("%s", s);
    int ans = solve(s);
    memset(dp, 0, sizeof(dp));
    memset(a, 0, sizeof(a));
    scanf("%s", s);
    int ans1 = dp[len - 1][a[len - 1]][0][1] + solve(s);
    printf("%d\n", ans1 - ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值