https://codeforces.com/gym/102452/problem/J
队友一开始就给我来了个"这不是基本操作吗"f(x)=(\sum{d(x,i)} ^2 - \sum{(d(x,i))^2})/2,于是就把要维护的东西转成只与当前坐标有关了,然后由于一个总和平方和一个每个数要分开算,且后面有个/2,那么要把m=2m,然后120空间也开不下,时间也不太行,陷入漫长的自闭
然后发现只要维护前缀和和剩下的两维就好了,没有这个/2,那么60的空间就能卡下,时间也优化了4倍,,,就简单多了
dp[k][x][y]为到第k位前缀和为x的情况下,y为前i为x和f(x)的差%m
那么假设当前选择数字i,那么转移就是dp[k][x][y]->dp[i][x+i][y+x*i-i*mi[len-i]],因为新进1位f(x)就增加前缀和*i
最后到底就只能y==0时,有一个解
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=5e3+10;
const int mod=1e9+7;
int llen,rlen,m,len,mt;
ll ans;
int a[maxl];
ll dp[maxl][61][61][2];
int clk[maxl][61][61][2];
int mi[maxl];
char l[maxl],r[maxl];
inline void prework()
{
scanf("%s",l+1);
llen=strlen(l+1);
scanf("%s",r+1);
rlen=strlen(r+1);
scanf("%d",&m);
}
inline void add(ll &x,ll y)
{
x=(x+y)%mod;
}
inline int mo(int x)
{
return (x%m+m)%m;
}
inline ll dfs(int k,int x,int y,bool f)
{
if(k>len)
return y==0;
if(clk[k][x][y][f]==mt)
return dp[k][x][y][f];
int up=f?a[k]:9;
dp[k][x][y][f]=0;
for(int i=0;i<=up;i++)
add(dp[k][x][y][f],dfs(k+1,(x+i)%m,mo(y+x*i-mi[len-k]*i),f && (i==up)));
clk[k][x][y][f]=mt;
return dp[k][x][y][f];
}
inline void mainwork()
{
len=rlen;mi[0]=1;++mt;
for(int i=1;i<=len;i++)
a[i]=r[i]-'0',mi[i]=mi[i-1]*10%m;
ll tmp1=dfs(1,0,0,1);
len=llen;++mt;
for(int i=1;i<=len;i++)
a[i]=l[i]-'0';
ll tmp2=dfs(1,0,0,1);
int x=0;
for(int i=1;i<=llen;i++)
x=(x+mi[llen-i]*a[i])%m;
int fx=0;
for(int i=1;i<llen;i++)
for(int j=i+1;j<=llen;j++)
fx=(fx+a[i]*a[j])%m;
if(fx==x)
ans=((tmp1-tmp2+1)%mod+mod)%mod;
else
ans=((tmp1-tmp2)%mod+mod)%mod;
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}