解题思路
dp定义:
pos:表示位数
res:表示膜13的余数
op:表示关于出现13的状态,其中:
- op=0: 当前位不为1,下一位要找1
- op=1:当前位为1,下一位想找3
- op=2:当前已有13,无欲无求
试填法
若当前位置之前的位置x 都填了s[x] (s[i]指给出的n对应数位上的数),则这个位置就有上限了,s为s[i]
否则s=9,0~9都可以填。
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int mod=13;
int s[20],c[20],power[20],f[20][13][3];
int n;
int check(int v13,int val)
{
if(v13==0)//当前要找1
{
if(val==1) return 1;//找到了,则下一步要找3
return 0;
}
else if(v13==1)//想找3
{
if(val==1) return 1;//又找到了1,没事,下一步还要找3
if(val==3) return 2;//找到3了,开心,下一步可以随便玩了
return 0;
}
else//已经有13,无欲无求
return 2;
}
int dfs(int pos,int res,int op,int limit)
{
if(!limit&&f[pos][res][op]>=0)return f[pos][res][op];
if(pos==0)return op==2&&res==0;
int s=0,ans=0,rest;
if(!limit)
s=9;
else s=c[pos];
for(int i=0;i<=s;i++)
{
/*rest=(res+13-i*power[pos-1]%13)%13;//另一种op定义的码,但一直没过,0表示没13,1表示有3,2表示有13,巨爷帮忙看看呗
if(op==2)
{
ans+=dfs(pos-1,rest,2,limit&&(i==s));
if(i==1)
ans+=dfs(pos-1,rest,1,limit&&(i==s));
}
if(op==1&&i==3)ans+=dfs(pos-1,rest,1,limit&&(i==s))+dfs(pos-1,rest,0,limit&&(i==s));
if(op==0)
{
if(i!=1&&i!=3)ans+=dfs(pos-1,rest,1,limit&&(i==s));
if(i!=3)ans+=dfs(pos-1,rest,0,limit&&(i==s));
}*/
ans+=dfs(pos-1,(res*10+i)%mod,check(op,i),limit&&i==s);
}
if(!limit)f[pos][res][op]=ans;
return ans;
}
int solve(int n){
int cnt=1,x=n;
while(x>0)
{
c[cnt++]=x%10;
x=x/10;
}
return dfs(cnt-1,0,0,1);//从高位到低位枚举
}
int main(){
while(scanf("%d",&n)!=EOF)
{
memset(f,-1,sizeof(f));
printf("%d\n",solve(n));
}
}