吉哥系列故事——恨7不成妻
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 4450 Accepted Submission(s): 1450
依然单身!
吉哥依然单身!
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无关的数字的平方和。
3 1 9 10 11 17 17
236 221 0
分析:很容易的看出来是数位DP,然后很容易的看出来他的dp要有三维,即位置pos,数字之和sum,以及整个数字对7的模数num。最麻烦的就是平方和的计算。·一开始自信满满的声明了longlong的变量到pos等于0的时候计算这个数的平方。wa了4发才浪子回头。。数字的范围是1e18的QAQ。那相乘肯定爆longlong了。。难道用大数?(自信的朋友可以去试试).然后参考了kuangbin的做法。如何求很多数的平方和呢?如下
一个十进制数可以写成X=ΣAi*Pi,(其中Ai为X每一位的值,Pi=10^i) 456 = 4*100+5*10+6*1;
因为(A+B)^2=A*A+2*A*B+B*B
(X1+X2+X3+...+Xn)^2=X1^2+2*X1*(X2+X3+...+Xn)+(X2+X3+...+Xn)^2
=X1^2+2*X1*(X2+X3+...+Xn)+X2^2+2*X2*(X3+...+Xn)+(X3+...+Xn)^2
......这样递推下去就可以把一个数转换为如456^2 = (4*100+5*10+6*1)^2 ;234^2 = (2*100+3*10+4*1)^2;那么456^2+234^2 = 400^2+56^2+2*400*56+200^2+34^2+2*200*34 = (400^2+200^2)+2*(400*56+200*34)+(56^2+34^2(这个括号里面两位数的还可以继续往下递推))。
上面的栗子展示了平方和结合在一起如何计算的方法:
首先我们要有当前位i.... ans1 = (i*pi)^2;如400,200,
其次我们要当前位之后的数字之和su。,56,34. ans2 =2*(su*i*pi);
最后,因为我们是要计算多个数的平方和,因此在当前状态下肯定不止一个数字可以到达。所以还需要存储一个cnt计数。最终答案是cnt*(ans1+ans2).
综上:在dp时,记录当前状态合法数的数量cnt,当前状态之后的和su,平方和po
A=Ai*Pi
now.cnt=now.cnt+nxt.cnt;
now.su=now.su+nxt.su+A*nxt.cnt;//因为su是计算和的,所以su实际上已经是cnt个数的累加了。now.po=now.po+A*A*nxt.cnt+2*A*nxt.su+nxt.po;
代码如下:
/* Author:kzl */
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MOD = 1e9 + 7;
typedef long long LL;
int digit[20];
LL p[20];
struct My{
int cnt,su,po;
My(){}
My(int a,int b,int c):cnt(a),su(b),po(c){}
}dp[20][200][10];
My dfs(int pos,int sum,int num,int jud){
if(pos==0){
My m;
if(num==0||sum%7==0)m.cnt = 0;
else m.cnt = 1;
m.su = m.po = 0;
return m;
}
if(!jud&&dp[pos][sum][num].cnt!=-1)return dp[pos][sum][num];
int sz = jud?digit[pos]:9;
My tmp,ans;
ans.cnt=ans.su=ans.po=0;
for(int i=0;i<=sz;i++)
{
if(i==7)continue;
tmp = dfs(pos-1,sum+i,(num*10+i)%7,jud&&(i==sz));
ans.cnt+=tmp.cnt;
ans.cnt%=MOD;
ans.su+=(tmp.su+ ((p[pos-1]*i)%MOD)*tmp.cnt%MOD )%MOD;
ans.su%=MOD;
ans.po+=(tmp.po + ( (2*p[pos-1]*i)%MOD )*tmp.su)%MOD;
ans.po%=MOD;
ans.po+=( (tmp.cnt*p[pos-1])%MOD*p[pos-1]%MOD*i*i%MOD );
ans.po%=MOD;
}
if(!jud)dp[pos][sum][num] = ans;
return ans;
}
My f(LL num)
{
int pos = 0;
while(num){
digit[++pos] = num%10;
num = num/10;
}
return dfs(pos,0,0,1);
}
int t;
LL l,r;
int main(){
p[0] = 1;
for(int i=1;i<20;i++)p[i] = (p[i-1]*10)%MOD;
for(int i=0;i<20;i++)for(int j=0;j<200;j++)for(int k=0;k<10;k++)dp[i][j][k].cnt = -1;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",(f(r).po-f(l-1).po+MOD)%MOD);
}
return 0;
}