这题的思路并不难,但是非常难做对,因为取模太恶心了,随时随地会溢出,并且因为取模的级别低,所以要多框括号防止先乘了再取模,还是会溢出
总之所有地方都取模,并且c++的模数可能是负数,所以需要手写一个mod,防止变成负数。
做法本身就是一个数位dp,这里要求平方和,我们之前一般做的都是求个数,按照求个数的方法来说,这题应该设计成f[][][][]表示前i个,最高位写j,整个数mod7的余数是k,各位之和的余数是l这样的状态
但是这题要求的是平方和,我们知道所有的数都可以表示成j*10^(i-1)+A,这个A代表最高位除外的数大小,这样通过高中所学的平方展开,就能发现我们需要保存的是个数,一位和以及平方和,才能求出这个式子
而预处理的状态就通过我们展开式就能发现了。
主要是取模太恶心了,真的恶心
#include<iostream> #include<vector> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=20; const int p=1e9+7; struct node{ ll s1; ll s2; ll s3; }f[N][10][8][8]; int power7[N], power9[N]; int mod(ll a,int b){ return (a%b+b)%b; } void init(){ int i,j,k,l,r; for(i=0;i<=9;i++){ if(i==7) continue; f[1][i][i%7][i%7].s1+=1; f[1][i][i%7][i%7].s2+=i; f[1][i][i%7][i%7].s3+=i*i; } ll power=10; for(i=2;i<N;i++,power*=10){ for(j=0;j<=9;j++){ if(j==7) continue; for(k=0;k<7;k++){ for(l=0;l<7;l++){ for(r=0;r<=9;r++){ if(r==7) continue; auto &v1 = f[i][j][k][l], &v2 = f[i - 1][r][mod(k - j * power, 7)][mod(l - j, 7)]; v1.s1=mod(v1.s1+v2.s1,p); v1.s2=mod(v1.s2+j*(power%p)%p*v2.s1%p+v2.s2,p); //v1.s3 = mod(v1.s3 + j * j * (power % p) % p* (power % p)%p* v2.s1 + v2.s3 + //2 * j * power % p * v2.s2, p); v1.s3=mod(v1.s3+j*(power%p)%p*(power%p)%p*j*(v2.s1%p)+2*j*power%p*v2.s2%p+v2.s3,p); } } } } } power7[0] = 1; for (int i = 1; i < N; i ++ ) power7[i] = power7[i - 1] * 10 % 7; power9[0] = 1; for (int i = 1; i < N; i ++ ) power9[i] = power9[i - 1] * 10ll % p; } node get(int i, int j, int a, int b){ int s3= 0, s1 = 0, s2 = 0; for (int x = 0; x < 7; x ++ ) for (int y = 0; y < 7; y ++ ) if (x != a && y != b) { auto v = f[i][j][x][y]; s1= (s1 + v.s1) % p; s2= (s2 + v.s2) % p; s3= (s3 + v.s3) % p; } return {s1, s2, s3}; } ll dp(ll n){ if(!n) return 0; vector<int> num; ll sign=n%p; while(n){ num.push_back(n%10); n/=10; } ll res=0; ll last1=0; ll last2=0; int i; for(i=num.size()-1;i>=0;i--){ int x=num[i]; int j; for(j=0;j<x;j++){ if(j==7) continue; int a=mod(-last1*power7[i+1],7); int b=mod(-last2,7); auto v=get(i+1,j,a,b); res = mod( res + (last1%p)*(last1%p)%p*power9[i + 1]%p*power9[i + 1]%p * v.s1 % p + v.s3 + 2*last1%p * power9[i + 1]%p*v.s2, p); } if(x==7) break; last1=10*last1+x; last2+=x; if(!i&&(last1%7)&&(last2%7)){ res=mod(res+sign%p*sign%p,p); //如果sign不在之前取模一次,这里会溢出,除非注意取模的优先级 } } return res; } int main(){ ll l,r; int t; cin>>t; init(); while(t--){ cin>>l>>r; cout<<mod(dp(r)-dp(l-1),p)<<endl; } }