1. 程式人生 > >[HDU4507] [2013TencentHackathon] 吉哥系列故事——恨7不成妻 [數位dp]

[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;
}