题目连接
单身!
依然单身!
吉哥依然单身!
DS级码农吉哥依然单身!
所以,他生平最恨情人节,不管是214还是77,他都讨厌!
吉哥观察了214和77这两个数,发现:
2+1+4=7
7+7=7*2
77=7*11
最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数!
什么样的数和7有关呢?
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
Input
输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
Output
请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。
Sample Input
3
1 9
10 11
17 17
Sample Output
236
221
0
题意:
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
求一个区间中与7无关的数的平方和
题解:我们首先,要算一段数的平方和应该怎么算,例如: (20 + 3)^2 = 20^2 + 2*20*3 + 3^2。20-23的平方和
= (20 + 1)^2 + (20 + 2)^2 + (20 + 3)^2 = 3*20^2 + 2*20*(1+2+3) + 1^2 + 2^2 + 3^2。例如当前为为pos,这里面包含三部分,一个是 (3*20^2)里面的3,表示yu7无关数的个数; 2*20*(1+2+3)里的(1+2+3)表示与7无关数的和;1^2 + 2^2 + 3^2这个就表示pos-1为的无关数的平方和。
所以我们要同时维护三个值,第一个无关数的个数很好维护,就是常规数位DP,第二个就是无关数的和,第三个就是无关数的平方和。细节看代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e3+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define mid (l+r)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int dir[4][2]= {0,1,0,-1,1,0,-1,0};
typedef long long ll;
using namespace std;
ll d[20];
int num[20];
struct node
{
ll cnt,sum,qsum;///cnt表示无关数的个数,sum表无关数的和,qsum表示无关数的平方和
} dp[20][10][10];
void init()///初始化
{
d[0]=1;///d[i]=10^i;
for(int i=1; i<=18; i++)
d[i]=(d[i-1]*10)%mod;
for(int i=0; i<20; i++)
for(int j=0; j<10; j++)
for(int k=0; k<10; k++)
dp[i][j][k].cnt=-1;
}
node dfs(int pos,int s_y,int s_s,int lit)
{
if(pos==-1)
{
node temp;
temp.cnt=(s_y&&s_s);///只有当余数都不为0时才与7无关
temp.sum=temp.qsum=0;
return temp;
}
if(!lit&&dp[pos][s_y][s_s].cnt!=-1)
return dp[pos][s_y][s_s];
int End=lit?num[pos]:9;
node ans;
ans.cnt=ans.qsum=ans.sum=0;
for(int i=0;i<=End;i++)
{
if(i==7)
continue ;
node temp=dfs(pos-1,(s_y*10+i)%7,(i+s_s)%7,lit&&i==End);
ans.cnt=(ans.cnt+temp.cnt)%mod;
ans.sum=(ans.sum+temp.cnt*d[pos]%mod*i+temp.sum)%mod;
///例如前面和为23,现在pos=3,有4个数满足,所以当前和应是23+1000*4;
///(21+22+23)^2=3*20^2 + 2*20*(1+2+3) + 1^2 + 2^2 + 3^2
ans.qsum=(ans.qsum+(2*d[pos]*i)%mod*temp.sum+temp.qsum)%mod;///相当于上式里的+2*20*(1+2+3) + 1^2 + 2^2 + 3^2
ans.qsum=(ans.qsum+(temp.cnt*d[pos])%mod*d[pos]%mod*i*i%mod)%mod;///相当于上式里的+3*20^2
}
if(!lit)
dp[pos][s_y][s_s]=ans;
return ans;
}
ll solve(ll n)
{
int len=0;
while(n)
{
num[len++]=n%10;
n/=10;
}
return dfs(len-1,0,0,1).qsum%mod;
}
int main()
{
int t;
init();
scanf("%d",&t);
while(t--)
{
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",(solve(r)-solve(l-1)+mod)%mod);
}
return 0;
}