[HDU4507] [2013TencentHackathon] 吉哥系列故事——恨7不成妻 [数位dp]

[ L i n k \frak{Link} ]


这个题目名字是什么网上冲浪的羞耻play吗(

乍一看好像是道数位dp;然而要求的是平方和。
在暂时没有其他思路的情况下——能不能用数位dp做平方和?

数位dp在搜索的时候是这么个样子的:比如说
abcdefghi
现在搜到:
9982|e|fghi
那么现在确定了前面的9982,当前这一位和之后的fghi都不确定。
在这一位上的搜索结果就覆盖了efghi所有的可行情况
那么很显然地,要求数的平方和也就是这个(9982efghi)的平方和
所以就是(998200000+efghi)的平方和。这个可以拆。
拆出来三个都可以求。
998200000²想必不用多说;
2×998200000×efghi只需要知道sum(efghi),这个也好求;
efghi²呢?注意到这也是平方和,改变现在的问题让这个变成子问题就好了。)


这道题的细节有点多。
仔细讨论一下吧,理清思路再敲键盘。


现在这道题目被拆解为六块,分别是三个条件和三个返回值。
三个条件:
 1.不能有某一位是7;
 2.数位和不被7整除;
 3.数不被7整除

对应的方法:
 1.在枚举当前数位的时候直接跳过
  if (i==7) continue;
 2.传递数位和对7取模的余数sum
 3.传递(当前确定下来的一部分)数对7取模的余数ori
  if (!pos) ... sum && ori ...


三个值:
 1.满足条件数的个数cnt=a
 2.满足条件数的和sum=b
 3.满足条件数的平方和sqr=c
对应地,枚举令 p o s \frak{pos} 位置上的值为 i \frak{i} ,有方程:
(以下记 f ( p o s , s u m , o r i ) \frak{f(pos,sum,ori)} f \frak{f} ,记 f ( p o s 1 , ( s u m + i ) % 7 , ( o r i 10 + i ) % 7 ) \frak{f(pos-1,(sum+i)\%7,(ori*10+i)\%7)} g \frak{g} 。)
 1: f . a = g . a \frak{f.a=\sum g.a}
 2: f . b = g . a i 1 0 p o s 1 + g . b \frak{f.b=\sum g.a*i*10^{pos-1}+\sum g.b}
 3: f . c = g . a ( i 1 0 p o s 1 ) 2 + 2 i 1 0 p o s 1 g . b + g . c \frak{f.c=\sum g.a*(i*10^{pos-1})^2+2i*10^{pos-1}\sum g.b+\sum g.c}

然后往里面放无数个mod((

边界:!pos时,return Struct_UserDefined(sum&&ori, 0, 0);


大家好 我是会忘记读入数据组数的那种傻吊
还会把1e9+7写成1e9+9的那种
还有两个很蠢的错误不过不是很好描述就不讲了

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<cmath>
#include<ctime>
using namespace std;
const long long mod = 1000000007;
long long bit[20];
long long tp[20];
struct sut {
	long long a, b, c;
	sut(long long x = 0, long long y = 0, long long z = 0) {
		a = x;
		b = y;
		c = z;
	}
} F[20][10][10];
sut dfs(int pos, int sum, int ori, bool limit) {
	if (!pos) return sut(sum && ori, 0, 0);
	if (!limit && F[pos][sum][ori].a != -1) return F[pos][sum][ori];
	sut ret, tmp;
	long long up = limit ? bit[pos] : 9;
	for (long long i = 0; i <= up; ++i) {
		if (i == 7) continue;
		tmp = dfs(pos - 1, (sum + i) % 7, (ori * 10 + i) % 7, limit && i == up);
		ret.a += tmp.a;
		ret.a %= mod;
		ret.b += (tmp.a * i % mod * tp[pos-1] % mod + tmp.b) % mod;
		ret.b %= mod;
		ret.c += tmp.a * i % mod * i % mod * tp[pos-1] % mod * tp[pos-1] % mod;
		ret.c %= mod;
		ret.c += (2ll * i % mod * tp[pos-1] % mod * tmp.b % mod + tmp.c % mod) % mod;
		ret.c %= mod;
//		cout << pos << " " << sum << " " << ori << " " << limit << " " << i << " " << ret.a << " " << ret.b << " " << ret.c << endl;
	}
	if(!limit) F[pos][sum][ori] = ret;
	return ret;
}
long long solve(long long x) {
	bit[0] = 0;
	while (x) {
		bit[++bit[0]] = x % 10;
		x /= 10;
	}
	return dfs(bit[0], 0, 0, true).c;
}
int main() {
	memset(F,-1,sizeof(F));
	tp[0] = 1;
	for (int i = 1; i <= 19; ++i) tp[i] = tp[i-1] * 10 % mod;
	int T;
	scanf("%d", &T); //**
	while (T--) {
		long long L, R;
		scanf("%lld%lld", &L, &R);
		printf("%lld\n", (solve(R) - solve(L-1) + mod) % mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Estia_/article/details/83479031
今日推荐