吉哥系列故事——恨7不成妻
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 957 Accepted Submission(s): 300
Problem Description
单身!
依然单身!
吉哥依然单身!
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
Sample Output
Source
2013腾讯编程马拉松初赛第一场(3月21日)
Recommend
liuyiding
思路:维护3个值,个数,总和,平方和。
第一个是与7无关的数的个数,就是简单的数位DP了,很常规
第二个与7无关的数的和的维护需要用到第一个个数。
处理到第pos个数位时,加上i*10^pos * 后面的个数
第三个的维护需要用到前面两个
(pre*10^pos + next)^2= (pre*10^pos)^2+2*pre*10^pos*next +next^2
#include<cstdio>
#include<cstring>
#include<iostream>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define clr(f,z) memset(f,z,sizeof(f))
#define LL __int64
#define ll(x) (1<<x)
using namespace std;
const LL mod=1e9+7;
class Edge
{ public:
LL sqrsum;///平方和
LL cnt;//个数
LL sum;//和
}dp[40][33][33];//位数,1,0;
LL p[21];
int bit[40],pos;
LL L,R;
Edge DP(int pp,int sb,int ss,bool big)//位和%7,和%7
{ Edge tmp,ret;
if(pp==0)
{
tmp.cnt=(sb!=0&&ss!=0);
tmp.sqrsum=tmp.sum=0;
return tmp;
}
if(big&&dp[pp][sb][ss].cnt!=-1)
return dp[pp][sb][ss];
int kn=big?9:bit[pp];
tmp.cnt=tmp.sqrsum=tmp.sum=0;
FOR(i,0,kn)
{
if(i==7)continue;//不能含7
ret=DP(pp-1,(sb+i)%7,(ss*10+i)%7,big||kn!=i );
tmp.cnt=(tmp.cnt+ret.cnt)%mod;
tmp.sum=(tmp.sum+ret.sum+ret.cnt*((p[pp-1]*i)%mod) )%mod;
tmp.sqrsum=(tmp.sqrsum+ret.sqrsum+(((2*p[pp-1]*i)%mod)*ret.sum)%mod)%mod;
tmp.sqrsum=(tmp.sqrsum+(ret.cnt*(i*p[pp-1]%mod))%mod*(i*p[pp-1])%mod)%mod;
}
if(big)dp[pp][sb][ss]=tmp;
return tmp;
}
LL get(LL x)
{ pos=0;
while(x)
{
bit[++pos]=x%10;
x/=10;
}
LL ret=0;
return DP(pos,0,0,0).sqrsum;
}
int main()
{ int cas;
p[0]=1;p[1]=10;
FOR(i,2,20)
p[i]=(p[1]*p[i-1])%mod;//防溢出
while(~scanf("%d",&cas))
{
FOR(ca,1,cas)
{
FOR(i,0,30)FOR(j,0,22)FOR(k,0,22)
dp[i][j][k].cnt=-1;
// cin>>L>>R>>K;
scanf("%I64d%I64d",&L,&R);
LL ans=(get(R)-get(L-1)+mod)%mod;
printf("%I64d\n",ans);
//cout<<get(R)-get(L-1)<<endl;
}
}
return 0;
}