hdu3652 B-number(數位dp 前綴串思想)

題目

多組樣例,每次給定一個n(1<=n<=1e9),

求[1,n]中,數位表示中包含"13"子串,且數字能被13整除的數的數量

思路來源

https://blog.csdn.net/Code92007/article/details/86825530

題解

簡單題,我思路來源我自己

其實就是 Bomb 那道題的思想,感覺一年多,終於把其理解透徹了,

也會寫記憶化搜索的了,萬一哪天忘了呢,總結一下吧,

dp[i][j][k]表示當前第i位 狀態爲j 當前%13餘數爲k的方案數

狀態有012三種,分別對應不含13且末尾不是1,不含13且末尾是1,已含13三種狀態,

再根據最後填什麼,判斷和13前綴匹配多少,

%13=0,加一維餘數,用於記憶化

代碼

#include<bits/stdc++.h>
using namespace std;
const int N=20,mod=13;
typedef long long ll;
int t,k,len;
//不含13且末尾不是1 不含13且末尾是1 已含13(分別對應狀態0 1 2)
ll l,r,a[N],sz[N][3][mod];//dp[i][j][k]:表示i位 當前狀態爲j 當前餘數爲k的方案數
ll dfs(int pos,int st,int sum,bool lim){
    //printf("st:%d sum:%d\n",st,sum);
	if(pos==0){
        return st==2 && sum==0;
	}
	if(~sz[pos][st][sum] && !lim)return sz[pos][st][sum];
    ll ret=0;
    int up=lim?a[pos]:9;
    if(st==2){
        for(int i=0;i<=up;++i){
            ret+=dfs(pos-1,st,(sum*10+i)%mod,lim && i==up);
        }
    }
    else if(st==1){
        for(int i=0;i<=up;++i){
            ret+=dfs(pos-1,(i==3?2:(i==1?1:0)),(sum*10+i)%mod,lim && i==up);
        }
    }
    else if(st==0){
        for(int i=0;i<=up;++i){
            ret+=dfs(pos-1,i==1?1:0,(sum*10+i)%mod,lim && i==up);
        }
    }

    if(!lim)sz[pos][st][sum]=ret;
    return ret;
}

ll part(ll x){
	len=0;
	while(x)a[++len]=x%10,x/=10;
	return dfs(len,0,0,1);
}

int main(){
    memset(sz,-1,sizeof sz);
    while(~scanf("%lld",&r)){
        printf("%lld\n",part(r));
    }
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章