您的位置:首页 > 其它

BZOJ 1026 [SCOI2009]windy数

2017-05-29 11:53 155 查看

1026: [SCOI2009]windy数

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,统计类问题。上下界均在int范围内,故不必用long long(这样的判断是很有必要的)。

  包括A,B。我们通常可以方便算出1~n-1的范围内符合条件的总数。所以,只需要1~(A+1)-1减去1~B-1即可。

  DP方程很好写,但统计确实需要分段。本人最开始想少做些事情,但JIJI了(否则极复杂),也算是刷新了对数位DP的理解。

1~9,10~99,100~999,1000~9999……(先把位数为1至cnt-1计入)

100..0~(x-1)99..9(确定最高位 )

x00..0~x(y-1)9..9,xy0..0~xy(z-1)9..9,……,(高位到低位,如果高位已经出现非法,直接退出)

/**************************************************************
Problem: 1026
User: Doggu
Language: C++
Result: Accepted
Time:0 ms
Memory:820 kb
****************************************************************/

#include <cstdio>
const int N = 15;
int a, b, f
[10], ans;
int abs(int a) {return a>0?a:-a;}
int DP(int k,int i) {
if(f[k][i]) return f[k][i];
if(k==1) return  f[k][i]=1;
for( int j = 0; j <= 9; j++ ) if(abs(i-j)>=2) f[k][i]+=DP(k-1,j);
return f[k][i];
}
void CAL(int num,int delta) {//cal 0~num-1
int digit
, cnt = 0;
while(num) digit[++cnt]=num%10,num/=10;
for( int bit = 1; bit < cnt; bit++ )  //先把长度为1至cnt-1计入
for( int i = 1; i < 10; i++ )
ans += delta*DP(bit,i);
for( int i = 1; i < digit[cnt]; i++ )   //确定最高位
ans += delta*DP(cnt,i);
for( int bit = cnt-1; bit >= 1; bit-- ) {
for( int i = 0; i < digit[bit]; i++ ) if(bit==cnt||abs(i-digit[bit+1])>=2) ans += delta*DP(bit,i);
if(abs(digit[bit]-digit[bit+1])<2) break;//如果高位已经出现非法,直接退出
}
}
int main() {
scanf( "%d%d", &a, &b );
CAL(b+1,+1);
CAL(a,-1);
printf("%d\n",ans);
return 0;


数位DP
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: