【HDU 4507】吉哥系列故事——恨7不成妻

【题目】

传送门

Problem Description

单身!
依然单身!
吉哥依然单身!
DS 级码农吉哥依然单身!
所以,他生平最恨情人节,不管是 214 214 214 还是 77 77 77,他都讨厌!

吉哥观察了 214 214 214 77 77 77 这两个数,发现:

2 + 1 + 4 = 7 2+1+4=7 2+1+4=7
7 + 7 = 7 ∗ 2 7+7=7*2 7+7=72
77 = 7 ∗ 11 77=7*11 77=711

最终,他发现原来这一切归根到底都是因为和 7 7 7 有关!所以,他现在甚至讨厌一切和 7 7 7 有关的数!

什么样的数和 7 7 7 有关呢?

如果一个整数符合下面 3 3 3 个条件之一,那么我们就说这个整数和 7 7 7 有关——

  1. 整数中某一位是 7 7 7
  2. 整数的每一位加起来的和是 7 7 7 的整数倍;
  3. 这个整数是 7 7 7 的整数倍;

现在问题来了:吉哥想知道在一定区间内和 7 7 7 无关的数字的平方和。

Input

输入数据的第一行是 c a s e case case t t t 1 ≤ t ≤ 50 1 \le t ≤ 50 1t50),然后接下来的 t t t 行表示 t t t c a s e case case;每个 c a s e case case 在一行内包含两个正整数 l , r l, r l,r 1 ≤ l ≤ r ≤ 1 0 18 1 \le l \le r \le 10^{18} 1lr1018)。

Output

请计算 [ l l l , r r r ] 中和 7 7 7 无关的数字的平方和,并将结果对 1 0 9 + 7 10^9 + 7 109+7 求模后输出。

Sample Input

3
1 9
10 11
17 17

Sample Output

236
221
0


【分析】

终于把这道题弄出来了。。。

看到数据范围,很显然是一道数位 d p dp dp

其实,如果只是统计与 7 7 7 无关的数的个数,就是常规操作,直接套板子就行了

但是现在是求平方和,该怎么办呢?

对每个节点都保存一个三元组, n u m num num 为合法的数的个数, s u m sum sum 为合法的数的和, s q u squ squ 为合法的数的平方和

首先,我们先思考简单一点的,怎么求与 7 7 7 无关的数的

假设现在 d p dp dp 到了第 p o s pos pos 位,这一位填的数为 i i i,那么加上这一位 i i i 产生的贡献,和就是

n o w . s u m + = t e m p . s u m + t e m p . n u m ∗ i ∗ 1 0 p o s − 1 now.sum+=temp.sum+temp.num*i*10^{pos-1} now.sum+=temp.sum+temp.numi10pos1

n o w . s u m now.sum now.sum 记录的就是当前位置的和, t e m p . s u m temp.sum temp.sum 是不算上当前位置(就是之前的数的和)的和

现在就考虑如何算平方和 a a a 表示不算上当前位,之前合法的数)

n o w . s q u = ∑ ( a + i ∗ 1 0 p o s − 1 ) 2 now.squ=\sum(a+i*10^{pos-1})^2 now.squ=(a+i10pos1)2

b = i ∗ 1 0 p o s − 1 b=i*10^{pos-1} b=i10pos1,并拆开来化简得到

n o w . s q u = ∑ ( a 2 + 2 a b + b 2 ) = ∑ a 2 + 2 b ∑ a + ∑ b 2 now.squ=\sum (a^2+2ab+b^2)=\sum a^2+2b\sum a+\sum b^2 now.squ=(a2+2ab+b2)=a2+2ba+b2

可以发现, ∑ a 2 \sum a^2 a2 就是 t e m p . s q u temp.squ temp.squ ∑ a \sum a a 就是 t e m p . s u m temp.sum temp.sum,有关于 b b b 的暴力计算就行了


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define Mod 1000000007
using namespace std;
int a[20],Pow[20];
struct dp{long long num,sum,squ;}f[20][10][10][2];
dp search(int p,int v1,int v2,bool limit)
{
	int i,up;
	dp ans=(dp){0,0,0};
	if(!p)  return (dp){v1&&v2,0,0};
	if(~f[p][v1][v2][limit].num)  return f[p][v1][v2][limit];
	up=limit?a[p]:9;
	for(i=0;i<=up;++i)
	{
		if(i==7)  continue;
		dp temp=search(p-1,(v1+i)%7,(v2*10+i)%7,limit&&a[p]==i);
		ans.num=(ans.num+temp.num)%Mod;
		ans.sum=(ans.sum+temp.sum+1ll*i*Pow[p-1]%Mod*temp.num%Mod)%Mod;
		ans.squ=(ans.squ+temp.squ+2ll*i*Pow[p-1]%Mod*temp.sum%Mod+temp.num*i*i%Mod*Pow[p-1]%Mod*Pow[p-1]%Mod)%Mod;
	}
	f[p][v1][v2][limit]=ans;
	return ans;
}
long long solve(long long x)
{
	int p=0;
	while(x!=0)
	{
		a[++p]=x%10;
		x/=10;
	}
	memset(f,-1,sizeof(f));
	return search(p,0,0,true).squ;
}
int main()
{
	int n,i;
	long long l,r;
	scanf("%d",&n);
	Pow[0]=1;
	for(i=1;i<20;++i)
	  Pow[i]=10ll*Pow[i-1]%Mod;
	for(i=1;i<=n;++i)
	{
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",(solve(r)-solve(l-1)+Mod)%Mod);
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值