hdu 4507 吉哥系列故事——恨7不成妻(数位DP,5级)
吉哥系列故事——恨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无关的数字的平方和。
依然单身!
吉哥依然单身!
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
Source
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
第二个与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; }
The article write by nealgavin