数位DP
F[A][B][C][L][R]表示当前为第A位 前面的和为B上一次剩下的可用贡献为C
是否到了上下界
同时需要记录一下每一个F对应的C
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
char c;
#define ll long long
inline void read(ll &a){a=0;do c=getchar();while(c<'0'||c>'9');while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();}
struct Rec
{
ll L,R,A,B,C;
ll ans;
ll res;
inline friend bool operator !=(Rec a,Rec b){return (a.L^b.L)|(a.R^b.R)|(a.A^b.A)|(a.B^b.B)|(a.C^b.C);}
};
const
int Mod=1264273;
struct Chain
{Rec op;Chain *next;}*T[Mod];
inline int Hash(Rec a){return ((a.L+a.R*11+a.A*121+a.B*121*11+a.C*121*121)%Mod+Mod)%Mod;}
Chain *Res;
inline void Add(Rec A){int pl=Hash(A);Chain *n=new Chain;n->next=T[pl];T[pl]=n;n->op=A;}
bool Find(Rec A,Chain*C)
{if(!C)return false;
if(C->op!=A)
return Find(A,C->next);
return Res=C,true;}
int LA[1001],RA[1001];
ll top,n;
ll l,r,k;
ll Pow(ll A,ll B)
{
if(B==0)return 1;
if(B==1)return A;
ll P=Pow(A,B>>1);
return B&1?P*P*A:P*P;
}
ll Ans(ll A,ll B,ll &C,ll L,ll R)
{
//printf ("%lld %lld %lld %lld %lld\n",A,B,C,L,R);
//if(R<L)return 0;
// if(B>=k&&L==-1&&R==10)
// {
// return C=0,Pow(10,top-A+1);
// }
if(A>top)
return (B+C>=k)?(C=0,1):(C+=B,0);
Rec Cur=(Rec){L,R,A,B,C};
ll AS=C;
if(Find(Cur,T[Hash(Cur)]))return //printf("%lld %lld %lld %lld %lld %lld\n",top-A+1,B,C,L,R,(Res->op).ans),
C=(Res->op).res,(Res->op).ans;
Cur.ans=0;
if(L!=-1)
if(L^R)
Cur.ans+=Ans(A+1,B+L,C,LA[A+1],10);
else Cur.ans+=Ans(A+1,B+L,C,LA[A+1],RA[A+1]);
for(int i=L+1;i<R;i++)
Cur.ans+=Ans(A+1,B+i,C,-1,10);
if(R!=L)
if(R!=10)
Cur.ans+=Ans(A+1,B+R,C,-1,RA[A+1]);
Cur.res=C;
Add(Cur);
return //printf("%lld %lld %lld %lld %lld %lld\n",top-A+1,B,AS,L,R,Cur.ans),
Cur.ans;
}
int main()
{
read(l),read(r),read(k);
top=1,n=1;
while(n<=r)top++,n=(n<<1)+(n<<3);
top--,n/=10;
bool fl=false;
for(int i=1;i<=top;i++)
{
RA[i]=(r/n)%10;
LA[i]=(l/n)%10;
//if(LA[i])fl=true;
//if(!fl)LA[i]=-1;
n/=10;
}
ll A=0;
ll ans=Ans(1,0,A,LA[1],RA[1]);
printf("%lld\n",ans);
return 0;
}