测试地址:Seven
作法: 本题须要用到数位DP。
是的,我看这题题目名字实在太长,就本身给取了个名字…首先看它给的条件,若是只求数字个数的话,很是明显是数位DP的形式,只须要设
为前
位中,不卡上界的,数位和对
的余数为
,数对
的余数为
的数字的个数,很容易就能转移。而要求数字的和较难一点,但咱们也能较快地想出转移。而如今要求数字的平方和,这就有点复杂了。
然而实际上也不很复杂,你只须要一个结论:一些数的平方和,等于这些数和的平方,减去这些数两两间的乘积之和乘
。这个结论也很容易理解,由于
,移项便可获得上面的结论。这样一来,咱们须要求
,表示知足对应条件(和上面状态定义同样,就不重复写了)的数的和,还有
,表示知足对应条件的数两两之间乘积的和。
咱们发现全部转移均可以转化为如下问题:咱们有两个集合,分别求出了对应的
和
,它们合并以后的
和
怎么求?这个比较好推,就本身推一下就好了,实在不懂就看我代码。还有一个问题是,咱们有一个集合,求出了对应的
和
,那么在这些集合的数以后添加一位数
后,集合的
和
怎么变化?这个就稍微复杂一些,以三个数的集合
为例,令新加的位为
,则:
根据这两个式子咱们能够找到规律,首先
不变,
就等于原来的
乘
加上
乘
,而
等于原来的
乘
,加上
原来的
,最后加上
。
有了这些东西,就能够解决转移的问题了,像模板数位DP同样作就好了。
如下是本人代码:php
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000007; const ll inv2=500000004; int T,n; ll s[25],num[25][7][7],f[25][7][7],g[25][7][7]; void update(int dgt,int j,int k,ll nowf,ll nowg,ll nownum) { g[dgt][j][k]=(g[dgt][j][k]+nowg+nowf*f[dgt][j][k])%mod; f[dgt][j][k]=(f[dgt][j][k]+nowf)%mod; num[dgt][j][k]=(num[dgt][j][k]+nownum)%mod; } ll solve() { int nowi=0,nowj=0,nowk=0; ll nowsum=0; memset(f[n+1],0,sizeof(f[n+1])); memset(g[n+1],0,sizeof(g[n+1])); memset(num[n+1],0,sizeof(num[n+1])); for(int dgt=n;dgt>=1;dgt--) { memset(f[dgt],0,sizeof(f[dgt])); memset(g[dgt],0,sizeof(g[dgt])); memset(num[dgt],0,sizeof(num[dgt])); for(int j=0;j<7;j++) for(int k=0;k<7;k++) for(int now=0;now<=9;now++) { if (now==7) continue; int newj=(j+now)%7,newk=(k*10ll+now)%7; ll nowf=(f[dgt+1][j][k]*10ll%mod+now*num[dgt+1][j][k]%mod)%mod; ll nowg=g[dgt+1][j][k]*100ll%mod; nowg=(nowg+f[dgt+1][j][k]*now%mod*10ll%mod*(num[dgt+1][j][k]-1ll+mod)%mod)%mod; nowg=(nowg+num[dgt+1][j][k]*(num[dgt+1][j][k]-1ll)%mod*inv2%mod*now*now%mod)%mod; ll nownum=num[dgt+1][j][k]; update(dgt,newj,newk,nowf,nowg,nownum); } if (dgt<n&&(!nowi)) { for(int now=0;now<s[dgt];now++) { if (now==7) continue; int newj=(nowj+now)%7,newk=(nowk*10ll+now)%7; update(dgt,newj,newk,(nowsum*10ll+now)%mod,0ll,1ll); } } nowi=(nowi||(s[dgt]==7)); nowj=(nowj+s[dgt])%7; nowk=(nowk*10ll+s[dgt])%7; nowsum=(nowsum*10ll+s[dgt])%mod; for(int now=1;now<=((dgt==n)?(s[dgt]-1):9);now++) { if (now==7) continue; update(dgt,now%7,now%7,now,0ll,1ll); } } f[0][0][0]=g[0][0][0]=num[0][0][0]=0; for(int j=1;j<7;j++) for(int k=1;k<7;k++) update(0,0,0,f[1][j][k],g[1][j][k],num[1][j][k]); ll ans=((f[0][0][0]*f[0][0][0]%mod-g[0][0][0]*2ll)%mod+mod)%mod; if ((!nowi)&&nowj&&nowk) ans=(ans+nowsum*nowsum)%mod; return ans; } int main() { scanf("%d",&T); while(T--) { ll ans=0,x; scanf("%lld",&x); x--; if (x) { n=0; while(x) { s[++n]=x%10; x/=10; } ans=(mod-solve())%mod; } scanf("%lld",&x); n=0; while(x) { s[++n]=x%10; x/=10; } ans=(ans+solve())%mod; printf("%lld\n",ans); } return 0; }