传送门
好题啊。
我只会写
l
,
r
l,r
l,r都很小的情况(然而题上并没有这种数据范围)。
但这个dp转移式子可以借鉴。
我们用
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示当前在第i位,模7余j,当前位是k。
显然有
f
[
i
+
1
]
[
(
[
j
∗
10
+
l
)
f[i+1][([j*10+l)
f[i+1][([j∗10+l)%
7
]
[
l
]
+
=
f
[
i
]
[
j
]
[
k
]
7][l]+=f[i][j][k]
7][l]+=f[i][j][k]。
但是i上限
1
e
9
1e9
1e9,直接做会凉。
于是我们构造矩阵来优化。
我们的矩阵只跟第二,三维有关。
准确的说,令
t
=
10
∗
j
+
k
t=10*j+k
t=10∗j+k,
t
′
=
(
(
j
∗
10
+
l
)
t'=((j*10+l)
t′=((j∗10+l)%
7
)
∗
10
+
l
7)*10+l
7)∗10+l。
那么这个t->t’是合法的,就对矩阵对应的
v
a
l
[
t
]
[
t
′
]
val[t][t']
val[t][t′]有1的贡献。
然后会发现需要记录矩阵的前缀和。
这个我们在矩阵最后添一列1来算就行了。
然后就快速幂弄一弄就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 72
#define mod 1000000007
using namespace std;
int T,K;
ll L,R;
struct Matrix{ll val[N][N];Matrix(){memset(val,0,sizeof(val));}};
inline Matrix operator*(Matrix a,Matrix b){
Matrix c;
for(int i=0;i<N;++i)for(int j=0;j<N;++j)for(int k=0;k<N;++k)
(c.val[i][j]+=a.val[i][k]*b.val[k][j]%mod)%=mod;
return c;
}
inline Matrix operator^(Matrix A,int p){
Matrix ret;
for(int i=0;i<N;++i)ret.val[i][i]=1;
while(p){
if(p&1)ret=ret*A;
p>>=1,A=A*A;
}
return ret;
}
inline int calc(int i,int j){return i*10+j;}
int main(){
scanf("%d",&T);
while(T--){
scanf("%lld%lld%d",&L,&R,&K);
Matrix A,B;
for(int i=0;i<7;++i)for(int j=0;j<10;++j)for(int k=0;k<10;++k)
if(j+k!=K)++B.val[calc(i,j)][calc((i*10+k)%7,k)];
for(int i=0;i<10;++i)++B.val[i][N-1];
++B.val[N-1][N-1];
for(int i=1;i<10;++i)++A.val[0][calc(i%7,i)];
Matrix tmp1=A*(B^R),tmp2=A*(B^(L-1));
ll ans=((tmp1.val[0][N-1]-tmp2.val[0][N-1])%mod+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}