luoguP2657 [SCOI2009] windy 数 数位dp
基本上把数位dp那一套给忘了,今天重学一遍.
感觉采用递推的方式还是蛮方便的,然后要注意几个细节:
1. 通常算 f(x+1)=calc(1,x),这样更方便算一些.
2. 每种小于最大长度的所有结果都要累加.
3. 很多时候不要忘记 0 的贡献.
4. 要特判前缀合不合法.
code:
#include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; ll f[20][20]; int num[20],cnt; void init() { for(int i=0;i<10;++i) f[1][i]=1; for(int i=2;i<11;++i) for(int j=0;j<10;++j) for(int k=0;k<10;++k) if(abs(k-j)>=2) f[i][j]+=f[i-1][k]; } ll calc(ll x) { memset(num,0,sizeof(num)),cnt=0; do { num[++cnt]=x%10; x/=10; }while(x); ll ans=0; for(int i=1;i<cnt;++i) for(int j=1;j<10;++j) ans+=f[i][j]; for(int i=1;i<num[cnt];++i) ans+=f[cnt][i]; for(int i=cnt-1;i>=1;--i) { if(i+2<=cnt&&abs(num[i+1]-num[i+2])<2) break; for(int j=0;j<num[i];++j) if(abs(num[i+1]-j)>=2) ans+=f[i][j]; } return ans; } int main() { // setIO("input"); init(); ll L,R; scanf("%lld%lld",&L,&R); printf("%lld\n",calc(R+1)-calc(L)); return 0; }