题目如下
求[l , r] 中
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
吉哥想知道在一定区间内和7无关的数字的平方和,区间范围在1-10^18.
根据题意我们的状态为dp[i][j][k],表示之前的整数和对7的余数为j,之前的整数对7的余数为k,在第i位与7无关的数一共有多少个。
然后问题就是平方和的求解,假设数位dxxxxxxx,设当前位d的10次幂为x,后面的一串为y,那么平方和就为(x+y)^2=x^2+2*x*y+y^2。x^2就直接x^2乘以后面出现的次数,2*x*y为2*x*后面出现的每一位和。y^2即为下一层深度得到的值。代码如下
#include<stdio.h>
#include<string.h>
const int mod=1e9+7;
typedef long long ll;
int lbit[20],hbit[20];
ll ten[20];
struct node
{
ll sum,num,sqr;
bool flag;
node(ll _num,ll _sum,ll _sqr):num(_num),sum(_sum),sqr(_sqr){}
node():flag(false){}
}dp[20][7][7];
int max(int a,int b)
{
return a>b? a:b;
}
node dfs(int len,int sum7,int num7,bool lb,bool hb)
{
if(len==0)
{
if(sum7!=0&&num7!=0) return node(1,0,0);
else return node(0,0,0);
}
if(!lb&&!hb&&dp[len][sum7][num7].flag)
return dp[len][sum7][num7];
int sta=lb? lbit[len]:0;
int end=hb? hbit[len]:9;
node ret(0,0,0),tmp;
// printf("%d %d %d %d %d\n",len,sum7,num7,sta,end);
for(int i=sta;i<=end;i++)
{
if(i==7) continue;
tmp=dfs(len-1,(sum7+i)%7,(num7*10+i)%7,lb&&i==sta,hb&&i==end);
// printf("!%d %d %d %lld %lld %lld %lld %l10ld %lld\n",len,i,end,tmp.num,tmp.sum,tmp.sqr,ret.num,ret.sum,ret.sqr);
ret.num=(ret.num+tmp.num)%mod;
ret.sum=(ret.sum+i*ten[len-1]%mod*tmp.num%mod+tmp.sum)%mod;
ret.sqr=(ret.sqr+i*ten[len-1]%mod*i%mod*ten[len-1]%mod*tmp.num%mod+tmp.sqr+2*i*ten[len-1]%mod*tmp.sum%mod)%mod;
// printf("%d %d %d %lld %lld %lld %lld %lld %lld\n",len,i,end,tmp.num,tmp.sum,tmp.sqr,ret.num,ret.sum,ret.sqr);
}
if(!lb&&!hb)
{
dp[len][sum7][num7]=ret;
dp[len][sum7][num7].flag=true;
}
return ret;
}
ll solve(ll l,ll r)
{
memset(lbit,0,sizeof(lbit));
memset(hbit,0,sizeof(hbit));
int lidx=1,hidx=1;
while(l)
{
lbit[lidx++]=l%10;
l/=10;
}
while(r)
{
hbit[hidx++]=r%10;
r/=10;
}
return dfs(max(lidx-1,hidx-1),0,0,true,true).sqr;
}
int main()
{
int T;
ten[0]=1;
for(int i=1;i<20;i++)
ten[i]=(ten[i-1]*10)%mod;
scanf("%d",&T);
while(T--)
{
ll l,r;;
scanf("%lld %lld",&l,&r);
printf("%lld\n",solve(l,r));
}
}