BZOJ1026 [SCOI2009]windy数
Description
一个数被称为 windy 数,当且仅当其满足满足如下条件:
• 不含前导零
• 相邻两个数字之差至少为 2
求在 [ A, B ] 中 windy 数的个数。
Input
输入一行两个整数 A, B ( A≤B≤2∗109A≤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)); }