題目鏈接:K-lucky-number
因爲不是求個數,而是平方,所以我們dp方程需要維護多個值,出現次數,和,平方和。
然後每次和求個數一樣轉移即可。
相當於把每一位拆開,然後類似於秦九韶算法,從前往後維護。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int a[20],l,r,k,p[20]={1};
struct node{int cnt,s1,s2;}dp[20][40];
node dfs(int pos,int s,int lim){
if(!pos) return {s==0,0,0};
if(!lim&&dp[pos][s].s1!=-1) return dp[pos][s];
int up=lim?a[pos]:9; node res; res.cnt=res.s1=res.s2=0;
for(int i=0;i<=up;i++){
node tmp=dfs(pos-1,(s+i)%k,lim&&i==up);
res.cnt=(res.cnt+tmp.cnt)%mod;
res.s1=(res.s1+tmp.s1+tmp.cnt*i%mod*p[pos-1]%mod)%mod;
res.s2=(res.s2+tmp.s2+tmp.cnt*i%mod*i%mod*p[pos-1]%mod*p[pos-1]%mod+
2LL%mod*i%mod*tmp.s1%mod*p[pos-1]%mod);
}
if(!lim) dp[pos][s]=res;
return res;
}
inline int calc(int x){
int pos=0;
while(x) a[++pos]=x%10,x/=10;
return dfs(pos,0,1).s2;
}
inline void solve(){
cin>>l>>r>>k; memset(dp,-1,sizeof dp);
cout<<((calc(r)-calc(l-1))%mod+mod)%mod<<endl;
}
signed main(){
for(int i=1;i<=10;i++) p[i]=p[i-1]*10%mod;
int T; cin>>T; while(T--) solve();
return 0;
}