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
",calc(R+1)-calc(L));  
    return 0; 
}

  

原文地址:https://www.cnblogs.com/guangheli/p/13096323.html