BZOJ_1026_[SCOI2009]windy数_数位DP
BZOJ_1026_[SCOI2009]windy数_数位DP
题意:windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
学一下数位DP。
f[i][j]表示i位数以j开头的windy数个数。转移有f[i+1][k]+=f[i][j](abs(j-k)>=2)
答案转成[1~R]-[1~L-1]之后按位枚举,每次枚举到当前位上的数减1。
注意:
1.枚举到两位差2以内时停止枚举。
2.答案要加上位数比他小的所有windy数。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int f[15][15],a,b; int c[15],d[15]; int sol(int x){ int num=x,cnt=0,ans=0; while(num){ c[++cnt]=num%10; num/=10; }for(int i=1;i<=cnt;i++)d[i]=c[cnt-i+1]; for(int i=1;i<cnt;i++) for(int j=1;j<=9;j++)ans+=f[i][j]; for(int i=1;i<d[1];i++)ans+=f[cnt][i]; for(int i=2;i<=cnt;i++){ for(int j=0;j<d[i];j++){ if(d[i-1]-j<2&&j-d[i-1]<2)continue; ans+=f[cnt-i+1][j]; } if(d[i-1]-d[i]<2&&d[i]-d[i-1]<2)break; } return ans; } int main(){ for(int i=0;i<=9;i++)f[1][i]=1; for(int i=2;i<=10;i++){ for(int j=0;j<=9;j++){ for(int k=0;k<=9;k++){ if(k-j<2&&j-k<2)continue; f[i][j]+=f[i-1][k]; } } } scanf("%d%d",&a,&b); //sol(18717); printf("%d\n",sol(b+1)-sol(a)); } /* 18716 38434 5178*/