【luogu2657】【bzoj1026】 [SCOI2009]windy数 [动态规划 数位dp]
一本通说这是一道数位dp模板题 emmmmm 就是逐位确定
f[i][j]表示填了i位数其最高位数字为j 然后就去求可能方案数
分为
- 不满足x的位数的严格小于x的全部情况
- 和x的位数相同 但最高位小于x的最高为的全部方案数
- 和x的位数相同 有一位比x的对应位数小的全部方案数 其余位数对应数字都相同(这是数位dp常用的一个性质:对于一个小于n的数 它从高位到低位一定会出现某一位上的数字小于n所对应这一位上的数字)
PS 因为x不一定为windy数 所以在第三种方案时 我们遇到不满足为windy数时退出
只是我还没搞懂为什么输出dp(b)-dp(a-1)会错一个点
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<cmath> 6 #include<stack> 7 #include<algorithm> 8 using namespace std; 9 #define ll long long 10 #define rg register 11 const int N=2000000000+5,pw=11,inf=0x3f3f3f3f,P=19650827; 12 int a,b,f[pw+5][pw+5]; 13 ll base[pw+5]; 14 template <class t>void rd(t &x) 15 { 16 x=0;int w=0;char ch=0; 17 while(!isdigit(ch)) w|=ch=='-',ch=getchar(); 18 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 19 x=w?-x:x; 20 } 21 22 void prepare() 23 { 24 base[0]=1; 25 for(rg int i=1;i<=pw;++i) base[i]=base[i-1]*10; 26 for(rg int i=0;i<10;++i) f[1][i]=1;//初 27 for(rg int i=2;i<=pw;++i) 28 for(rg int j=0;j<10;++j) 29 for(rg int k=0;k<10;++k) 30 if(abs(j-k)>=2) f[i][j]+=f[i-1][k]; 31 } 32 33 int dp(int x) 34 { 35 int p,ans=0; 36 for(p=0;p<=pw;++p) if(base[p]>x) break; 37 if(!p) return ans; 38 for(rg int i=1;i<p;++i) 39 for(rg int j=1;j<10;++j) 40 ans+=f[i][j];//不满p位的 41 int pre=x/base[p-1];x%=base[p-1]; 42 for(rg int i=1;i<pre;++i) 43 ans+=f[p][i];//满足p位 但第p位数字小于x的 44 for(rg int i=p-1;i>0;--i) 45 { 46 int cur=x/base[i-1]; 47 for(rg int j=0;j<cur;++j) 48 if(abs(pre-j)>=2) ans+=f[i][j]; 49 if(abs(pre-cur)<2) break; 50 pre=cur,x%=base[i-1]; 51 } 52 return ans; 53 } 54 55 int main() 56 { 57 //freopen("in.txt","r",stdin); 58 //freopen("nocows.out","w",stdout); 59 prepare(); 60 rd(a),rd(b); 61 printf("%d",dp(b+1)-dp(a)); 62 return 0; 63 }