|
吉哥系列故事——恨7不成妻Time Limit: 1000/500 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 5721 Accepted Submission(s): 1864
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
31 910 1117 17
Sample Output
2362210
Source
Recommend
liuyiding
|
/**
题意相对来说比较清晰明了 寻找和7无关的数的平方和;
与7有关的定义:
<1>整数某一位是7
<2>整数每一位加起来和是7的倍数
<3>这个数是7的倍数
ans:区间内和7无关数的平方和
这个题十分的邪乎 求解的并不是满足条件的个数 而是算出平方的和
因此DP的时候需要维护三个值并用结构体进行存储
<1>符合条件的数的个数 cnt;
<2>符合条件数的和 sum;
<3>符合条件数的平方和 sqsum
由dfs推出返回的是next,当前结果的结构体是ans;
第一个是与7无关的数的个数,就是简单的数位DP了,很常规。
第二个与7无关的数的和的维护需要用到第一个个数
处理到第len个数位时,加上i*10^ pos * 后面的个数
简化为式子就是 next.sum+(10^len*i)*ans.cnt ;
第三个的维护需要用到前面两个
(i*10^pos + x)^2= (i*10^len)^2+2*i*10^len*x +x^2;
x为当前数的后半部分
类似于 1024 被拆分为1000+24 然后去平方这样子....
最后 整体还需要乘以next.cnt 由于后续记忆化的过程并不止出现一个
因此:ans.sqsum+=next.sqsum
ans.sqsum+=(2*10^len*i*x)*next.cnt=(2*10^len*i)*next.sum 为了化简设立第二个变量sum
ans.sqsum+=(10^len*i)^2*next.cnt
嗯嗯 大概就是这个样子了 最后把框架架好 注意取模就差不多了
*/
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=20+7;
const int mod=1e9+7;
struct node {
ll cnt;//与7无关的数的个数
ll sum;//与7无关的数和
ll sqsum;//平方和
}dp[maxn][maxn][maxn];//数位len 数字和%7 数字%7
int num[maxn];
ll fac[maxn];
node dfs(int len,int digit,int pre,bool end_flag){
if(len==-1){
node tmp;
tmp.cnt=(digit&&pre);
tmp.sum=tmp.sqsum=0;
return tmp;
}
if(!end_flag&&dp[len][digit][pre].cnt!=-1) return dp[len][digit][pre];
int maxx=end_flag?num[len]:9;
node next,tmp;
next.cnt=next.sqsum=next.sum=0;
for(int i=0;i<=maxx;i++){
if(i==7) continue;
tmp=dfs(len-1,(digit+i)%7,(pre*10+i)%7,end_flag&&i==maxx);
next.cnt+=tmp.cnt;
next.cnt%=mod;
next.sum+=(tmp.sum+(fac[len]*i%mod)*tmp.cnt%mod)%mod;
next.sum%=mod;
next.sqsum+=(tmp.sqsum+((2*fac[len]*i)%mod)*tmp.sum)%mod;
next.sqsum%=mod;
next.sqsum+=((tmp.cnt*fac[len]))%mod*fac[len]%mod*i*i%mod;
next.sqsum%=mod;
}
if(!end_flag) dp[len][digit][pre]=next;
return next;
}
ll solve(ll n){
int len=0;
while(n){
num[len++]=n%10;
n/=10;
}
return dfs(len-1,0,0,1).sqsum;
}
void init(){
fac[0]=1;
for(int i=1;i<=20;i++) fac[i]=fac[i-1]*10%mod;
for(int i=0;i<maxn-1;i++)
for(int j=0;j<maxn-1;j++)
for(int k=0;k<maxn-1;k++)
dp[i][j][k].cnt=-1;
}
int main (){
init();
int t;scanf("%d",&t);
ll l,r;
while(t--){
scanf("%I64d %I64d",&l,&r);
ll ans=solve(r)-solve(l-1);
ans=(ans+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}