题意: 在一定区间内和7无关的数字的平方和。
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
对于第一个条件:在DP中多开一维0/1表示前面的位数中是否出现1
对于第二个条件:在DP中多开一维表示前面位数的和对7取余
对于第三个条件:在DP中多开一维表示生成的这个数对7取余
那么考虑一下边界:
如果出现7并且两个取余都是0,那么这个数就是跟7相关。
然后再来维护一下平方和。
这里用一个sum来维护,具体公式就不推了很好推的。
还要维护个数和平方和,那么就开一个结构体来DP;
在进行维护数据时要注意公式的正确性和取模。
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<set>
#include<iostream>
using namespace std;
#define INF 0x7f7f7f7f
#define LL long long
const LL mod=1e9+7;
struct node
{
LL cnt;
LL sum;
LL sum2;
}dp[20][2][10][10];
int a[20];
LL l,r;
LL q(int x)
{
LL tmp=1;
for(int i=1;i<=x;i++)
{
tmp*=10;
tmp%=mod;
}
return tmp;
}
node dfs(int pos,int pre,int sta,int sa,int sb,bool limit)
{
if(pos==-1)
{
node tmp;
if(sta==1||sa%7==0||sb%7==0)
{
tmp.cnt=0;
tmp.sum=0;
tmp.sum2=0;
return tmp;
}
else
{
tmp.cnt=1;
tmp.sum=0;
tmp.sum2=0;
return tmp;
}
}
if(!limit&&dp[pos][sta][sa][sb].cnt!=-1)
return dp[pos][sta][sa][sb];
int up=limit ? a[pos] : 9;
node tmp;
tmp.cnt=tmp.sum=tmp.sum2=0;
for(int i=0;i<=up;i++)
{
node ttp=dfs(pos-1,i,sta||i==7,(sa+i)%7,(sb*10+i)%7,limit&&i==a[pos]);
if(ttp.cnt>=1)
{
LL x=i*q(pos);
x%=mod;
tmp.cnt+=ttp.cnt;
tmp.cnt%=mod;
if(pos==0)
tmp.sum+=i;
else
tmp.sum+=ttp.sum+x*ttp.cnt%mod;
tmp.sum%=mod;
tmp.sum2+=(((x*x)%mod)*ttp.cnt)%mod+((2*x)%mod)*ttp.sum%mod+ttp.sum2%mod;
tmp.sum2%=mod;
}
}
if(!limit)
dp[pos][sta][sa][sb]=tmp;
return tmp;
}
node solve(LL x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,-1,0,0,0,true);
}
int main()
{
int t;
for(int i=0;i<20;i++)
for(int j=0;j<2;j++)
for(int k=0;k<10;k++)
for(int kk=0;kk<10;kk++)
dp[i][j][k][kk].cnt=-1;
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&l,&r);
LL ans=(solve(r).sum2-solve(l-1).sum2);
if(ans<0)
ans+=mod;
printf("%I64d\n",ans);
}
return 0;
}