求出区间内有13作为连续子串且是13的倍数的数字的个数
思路:dp数组增加一维用来表示状态数字对13取模的余数就好了,然后状态转移的时候按照找出含有13的数字的个数就可以了,二维转移。
代码没有用传统的数位DP框架下的dfs函数写,用状态推的,这样的写法与用传统的dfs写法不同点在于dfs方法求出的数字包含了传入的数字本身,所以答案一般是solve(b)-solve(a-1),,,这题的递推写法求出的满足要求的数字个数就是不包含数字本身的个数,一般答案这样写:solve(b+1)-solve(a), 前两天还不明白为什么?多谢几个题就知道了。
#include<iostream>
#include<cstring>
#include<cstdio>
#define fuck(a) printf("%s\n", a);
using namespace std;
typedef long long LL;
const int MAXN =20;
LL dp[MAXN][MAXN][MAXN*100];
//dp[i][j][k] i表示当前位置,j表示支点位置,k表示位置i前面已经得到的力矩和
template<typename T>
T oabs(T a){return a<0?-a:a;}
int num[MAXN],len;
LL dfs(int pos,int o,int pre,bool limit)
{
if(pos<1)
{
return pre==0;
}
if(!limit&&~dp[pos][o][pre])return dp[pos][o][pre];
LL res =0 ;
int end = limit ?num[pos]:9;
for(int i=0;i<=end;i++)
{
res += dfs(pos-1,o,pre+(pos-o)*i,limit&&(i==end));
}
if(!limit)dp[pos][o][pre]=res;
return res;
}
LL solve(LL n)
{
//cout<<"this is n "<<n;
if(n==-1||n==0)return n+1;
len =1;
LL temp = n;
while(n)
{
num[len++]=n%10;
n/=10;
}
len--;
LL res =0;
for(int i=1;i<=len;i++)
{
res+=dfs(len,i,0,true);
}
return res-len+1;
}
int main()
{
freopen("data.in","r",stdin);
LL a,b;
int T;
memset(dp,-1,sizeof(dp));
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d",&a,&b);
LL r1=solve(b);
LL r2=solve(a-1);
printf("%I64d\n",r1-r2);
}
return 0;
}