您的位置:首页 > 其它

bzoj 1026 [SCOI2009]windy数(数位DP)

2016-01-11 21:32 441 查看

1026: [SCOI2009]windy数

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 4550 Solved: 2039
[Submit][Status][Discuss]

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 。

Source

【思路】

数位DP。

设f[i][j]表示i位数且最高位为j的数中windy数的个数。则有转移式:

f[i][j]=sigma{ f[i-1][k] } ( | j-k |>=2 )

统计:长度比len小的 -> 长度为len最高位比b[len]小的 -> 最高位为b[len],统计方法见代码。

需要注意的是最后一项统计时,如果枚举过程中发现n不满足windy数则不再枚举,另外还需要注意n的计入与否。

【代码】

#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 15;

int f

,b
;

void init() {
for(int i=0;i<10;i++) f[1][i]=1;
for(int i=2;i<=10;i++)
for(int j=0;j<10;j++) {
for(int k=0;k<=j-2;k++) f[i][j]+=f[i-1][k];
for(int k=j+2;k<10;k++) f[i][j]+=f[i-1][k];
}
}
int Fc(int n) {
if(!n) return 0;
int ans=0,len=0,flag=1;
while(n)
b[++len]=n%10 , n/=10;
for(int i=1;i<len;i++)                                //统计所有长度小于 len 的
for(int j=1;j<10;j++) ans += f[i][j];
for(int j=1;j<b[len];j++) ans += f[len][j];                //长度为 len 最高位比 b[len] 小的
for(int i=len-1;i;i--) {                            //统计最高位为 b[len] 的
for(int j=0;j<b[i];j++)
if(abs(b[i+1]-j)>=2) ans += f[i][j];
if(abs(b[i+1]-b[i])<2) {                        //n 不满足 不再统计后面的而且不计入 n
flag=0; break;
}
}
if(flag) ans++;                                        //计入 n
return ans;
}

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