BZOJ1026 [SCOI2009]windy数

Description

一个数被称为 windy 数,当且仅当其满足满足如下条件: 
• 不含前导零 
• 相邻两个数字之差至少为 2 
求在 [ A, B ] 中 windy 数的个数。

Input

输入一行两个整数 A, B ( AB2109A≤B≤2∗109 ) 。

Output

对于每组测试数据,输出一行一个整数,描述答案。

Sample Input

0 2000000000

Sample Output

127322182

 
 
题解:
做过的第一道数位dp,然而听说暴力可以AC……
好了,设dp[i][j]表示数位为i最高位为j的windy数数量,转移很好想把,枚举和j绝对值相差大于等于2的数字k,这个就是下一位了,显然把数量移交个他就行了,方程:dp[i+1][k]+=dp[i][j]。然而这题的关键不在方程,而是……
根本不知道ans存在哪!下面才是正文:
首先我们可以吧一个数分成3部分:
记len为有多少的数位;
1.先统计1~(100000(len个0)-1)中有多少个windy。
2.统计1000000~(最高位-1)的windy数。
3.统计剩下的。
具体看我代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int A,B;
int dp[12][12],a[12];
 
void cl(){
    memset(dp,0,sizeof(dp));
}
 
void make(){
    for(int i=0;i<=9;i++) dp[1][i]=1;
    for(int i=1;i<=9;i++)
    for(int j=0;j<=9;j++)
    for(int k=0;k<=9;k++)
    if(abs(j-k)>=2) dp[i+1][k]+=dp[i][j];
}
 
int get(int x){
    if(x<=0) return 0;
    int len=0,tot=0;
    memset(a,0,sizeof(a));
    while(x) {a[++len]=x%10;x/=10;}
    for(int i=1;i<a[len];i++) tot+=dp[len][i];
    for(int i=1;i<len;i++)
    for(int j=1;j<=9;j++) tot+=dp[i][j];
    for(int i=len-1;i>0;i--){
        for(int j=0;j<a[i];j++){
            if(abs(a[i+1]-j)>=2)
            tot+=dp[i][j];
        }
        if(abs(a[i+1]-a[i])<2) break;
    }
    return tot;
}
 
int main(){
    cl();
    make();
    scanf("%d%d",&A,&B);
    printf("%d",get(B)-get(A-1));
}

 

posted @ 2017-07-16 23:45  人间失格—太宰治  阅读(200)  评论(0编辑  收藏  举报