題目
多組樣例,每次給定一個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;
}