BZOJ1026:[SCOI2009]windy数——题解

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

Description

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

Input

  包含两个整数,A B。

Output

  一个整数

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

————————————————————————————————————

今天开始学数位dp了!

所以趁着这道题还简单赶紧记录下来。

设dp(n)表示0~n的windy数个数。

设f[i][j][0/1]表示当前处理到第i位数为j,此时前i位数比n的前i位数小于等于(为0)/大于(为1)的数的个数。

显然我们求a~b的个数可以利用前缀和,只需要求dp(b)再减去dp(a-1)即可。

那么对于函数dp(n),其主要流程:

1.将n拆成十进制数,存在数组中(这里数组为a,长度为len)

2.特殊处理第一层:

for(int i=0;i<=9;i++){
    if(i<=a[1])f[1][i][0]=1;
    else f[1][i][1]=1;
}

3.枚举i=2~len层并处理之,枚举当前层填充的数字j和上一层填充数字k。当符合windy数的条件时开始更新,更新方程较显然就不多说了:

if(j<a[i])
    f[i][j][0]+=f[i-1][k][0]+f[i-1][k][1];
else if(j==a[i])
    f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1];
else f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1];

4.得出答案。这里需要注意对于最后一层需要特殊处理防止越出0~n的范围。也很显然。

整套流程至此完毕,复杂度显然为log级别。

PS:判断是否为windy数很简单,这里用了一个辅助数组c[i][j]表示abs(i-j),借此判断能够美化代码(滑稽)

#include<cstdio>
#include<cstring>
using namespace std;
const int N=11;
int a[N],f[N][N][2],c[N][N];
int dp(int x){
    int len=0;
    while(x)a[++len]=x%10,x/=10;
    if(len==0)a[++len]=0;
    memset(f,0,sizeof(f));
    for(int i=0;i<=9;i++){
    if(i<=a[1])f[1][i][0]=1;
    else f[1][i][1]=1;
    }
    for(int i=2;i<=len;i++){
    for(int j=0;j<=9;j++){
        for(int k=0;k<=9;k++){
        if(c[j][k]>=2){
            if(j<a[i])
            f[i][j][0]+=f[i-1][k][0]+f[i-1][k][1];
            else if(j==a[i])
            f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1];
            else f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1];
        }
        }
    }
    }
    int ans=0;
    for(int i=1;i<=a[len];i++)ans+=f[len][i][0];
    for(int i=len-1;i;i--){
    for(int j=1;j<=9;j++){
        ans+=f[i][j][0]+f[i][j][1];
    }
    }
    return ans;
}
int main(){
    for(int i=0;i<=9;i++){
    for(int j=i;j<=9;j++){
        c[i][j]=c[j][i]=j-i;
    }
    }
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d
",dp(b)-dp(a-1));
    return 0;
}
原文地址:https://www.cnblogs.com/luyouqi233/p/8250249.html