您的位置:首页 > 其它

bzoj 1026 Windy数 数位DP

2015-01-11 16:00 176 查看

bzoj 1026 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

HINT

【数据规模和约定】

100%的数据,满足 1 <= A <= B <= 2000000000 。

倒过来数位DP,f[i][j]为从右数第i位为j的Windy数个数

f[i][j]+=f[i-1][k](k<=j-2||k>=j+2)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#define MAXN 10

using namespace std;

int f[MAXN][10];
int len;

inline int abs(int x)
{
return x>0 ? x :-x;
}
inline void init()
{
for(int i=0; i<10; i++)
f[0][i]=1;
for(int i = 1; i < MAXN; i++)
{
for(int j=0; j<=9; j++)
{
f[i][j]=0;
for(int k=0; k<=j-2; k++)
f[i][j]+=f[i-1][k];
for(int k=j+2; k<=9; k++)
f[i][j]+=f[i-1][k];
}
}
}
inline bool isWindy(int n)
{

while(n>=10)
{
if(abs(n%10-n/10%10)<2)
return false;
n/=10;
}
return true;
}
inline int getsum(int n)
{
if(n==0)return 1;
int res=0;
if(isWindy(n))
res++;
int a[MAXN+1];
len=0;
while(n>0)
{
a[len++]=n%10;
n/=10;
}
int i;
for(i=len-1; i>=0&&(i>=len-2||abs(a[i+1]-a[i+2])>=2); i--)
{
if(i==len-1)
{
for(int j=1; j<a[i]; j++)
res+=f[i][j];
for (int j = i - 1; j >= 0; j--)
for (int k = 1; k <= 9; k++)
res += f[j][k];
res++;

}
else
{
for (int j = 0; j <= a[i + 1] - 2 && j < a[i]; j++)
res += f[i][j];
for (int j = a[i + 1] + 2; j < a[i]; j++)
res += f[i][j];
}
}
return res;
}

int main()
{
int A,B;
init();
scanf("%d%d",&B,&A);
printf("%d\n",getsum(A)-getsum(B-1));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: