1. 程式人生 > WINDOWS開發 >luoguP2657 [SCOI2009] windy 數 數位dp

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,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; 
}