B-number
题目链接:https://vjudge.net/problem/HDU-3652
题意:如果一个数是13的倍数且数中含有13,那这个数是一个b数,问你1到n里有多少个b数。
思路:普通的数位dp,因为数中要含有13,可以用state来记录13状态,如果已经含有13了,那state=2,如果末尾是1,state=1,否则state=0。用mod记录前len位%13的结果,其他和模板差不多。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int dp[20][20][5]; int a[20]; //len代表当前枚举的位,mod代码前len%13的值,state代表是否已经含有13的状态,flag代表是否还是处于上边界 int dfs(int len,int mod,int state,bool flag) { if(len==0) return mod==0&&state==2; int up=flag?a[len]:9;//决定你枚举的上界是多少 if(!flag&&dp[len][mod][state]!=-1) return dp[len][mod][state];//如果不是处于上边界并且之前求过了值的话可以直接返回 int tmp=0; for(int i=0; i<=up; i++) { int mo=(mod*10+i)%13; int sta=state; if(state==0&&i==1) sta=1; else if(state==1&&i!=1&&i!=3) sta=0; else if(state==1&&i==3) sta=2; tmp+=dfs(len-1,mo,sta,flag&&i==a[len]); } if(!flag) dp[len][mod][state]=tmp;//求了值用dp存下,下次可以使用 return tmp; } int suan(int x) { int pos=0; while(x) { a[++pos]=x%10; x/=10; } return dfs(pos,0,0,true); } int main() { int n; memset(dp,-1,sizeof(dp)); while(~scanf("%d",&n)) { cout<<suan(n)<<endl; } }