bzoj1026: [SCOI2009]windy数(数位dp)
1026: [SCOI2009]windy数
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 8203 Solved: 3687
[Submit][Status][Discuss]
Description
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
Input
包含两个整数,A B。
Output
一个整数
Sample Input
【输入样例一】
1 10
【输入样例二】
25 50
1 10
【输入样例二】
25 50
Sample Output
【输出样例一】
9
【输出样例二】
20
9
【输出样例二】
20
HINT
【数据规模和约定】
100%的数据,满足 1 <= A <= B <= 2000000000 。
题解
第一次做数位dp的题(从1662滚过来)
这道题也算是挺裸的一道数位dp 只需要记录上一位就可以判断是否合法
状态转移方程:令f[i][j]表示前i位,最高位为j的方案数
f[i][j]=sum(f[i-1][k]) if(k-j>=2)
代码大体是照着 http://www.cnblogs.com/zbtrs/p/6105338.html 打的 我觉得讲的非常棒
对于几个可能不太好理解的位置我加了一点注释
/**************************************************************
Problem: 1026
User: a799091501
Language: C++
Result: Accepted
Time:0 ms
Memory:1292 kb
****************************************************************/
#pragma GCC optimize("O2")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<limits.h>
#include<ctime>
#define N 100001
typedef
long
long
ll;
const
int
inf=999999999;
const
int
maxn=2017;
using
namespace
std;
ll f[20][20],num[20];
inline
int
read()
{
int
f=1,x=0;
char
ch=
getchar
();
while
(ch>
'9'
|ch<
'0'
)
{
if
(ch==
'-'
)
f=-1;
ch=
getchar
();
}
while
(ch<=
'9'
&&ch>=
'0'
)
{
x=(x<<3)+(x<<1)+ch-
'0'
;
ch=
getchar
();
}
return
f*x;
}
void
init()
{
memset
(f,0,
sizeof
(f));
for
(
int
i=0;i<=9;i++)
f[1][i]=1;
//第一位所有数都是windy数
for
(
int
i=2;i<=10;i++)
for
(
int
j=0;j<=9;j++)
for
(
int
k=0;k<=9;k++)
if
(
abs
(j-k)>=2) f[i][j]+=f[i-1][k];
//第i位最高位为j的状态可以从每一个符合条件的i-1位最高位为k转移而来
}
ll solve(ll x)
{
memset
(num,0,
sizeof
(num));
if
(x==0)
return
0;
ll pos=0,ans=0;
while
(x)
{
num[++pos]=x%10;
x/=10;
}
for
(
int
i=1;i<pos;i++)
for
(
int
j=1;j<=9;j++)
//不含前导零,因此从1开始枚举
ans+=f[i][j];
for
(
int
i=1;i<num[pos];i++)
ans+=f[pos][i];
for
(
int
i=pos-1;i>=1;i--)
{
for
(
int
j=0;j<num[i];j++)
//枚举最高位的所有状态
if
(
abs
(j-num[i+1])>=2)
//上一位
ans+=f[i][j];
if
(
abs
(num[i+1]-num[i])<2)
break
;
//后面的答案不可能有贡献,跳出
if
(i==1)ans+=1;
}
return
ans;
}
int
main()
{
int
a=read(),b=read();
init();
cout<<solve(b)-solve(a-1);
}
就让我永远不在这里写下什么有意义的话——by 吉林神犇 alone_wolf