您的位置:首页 > 其它

HDU 4507 吉哥系列故事——恨7不成妻 (比较繁琐的数位DP)

2013-12-08 14:32 465 查看
题目链接 :http://acm.hdu.edu.cn/showproblem.php?pid=4507

题意 :找出[l, r]之间所有不满足以下任意一条的数的平方之和 :

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

思路 : 数位DP, 繁琐的是处理平方和,可以这样考虑当你算到len位的时候获得的数字是x,然后下一位放进去的数字是i,那么其实所获得的新的值应该是x + i * 10 ^ (len-1), 然后要计算它的平方, 那么展开后就是  x * x + f * f + 2 * f * x ;(f = i * 10 ^ (len - 1)),这样的话需要统计在前继状态中获得的所有满足条件的数的个数cnt, 所有满足条件的数的和s1, 所有满足条件的数的平方和s2.然后用GYZ的数位DP写法秒了, 注意下别溢出即可。

PS : 一开始打算是把当前算到的位置所获得数字平方和传进去, 但是空间更本就是开不下的。看了爱神(cxlove)的blog才发现原来可以倒的把数据返回来, 这样就不需要担心爆内存了。

#include
#include
#include

using namespace std;
typedef __int64 lld;
const int mod = 1e9 + 7;

int bit[20];
lld cnt[20][2][7][7], s1[20][2][7][7], s2[20][2][7][7];
lld Fac[20];

struct Bo{
lld cnt, s1, s2;
Bo(){}
Bo(lld a, lld b, lld c) : cnt(a), s1(b), s2(c){}
};

Bo dfs(int len, int a, int b, int c, int fp){
if (!fp && cnt[len][a][b][c] != (lld)-1){
return Bo(cnt[len][a][b][c], s1[len][a][b][c], s2[len][a][b][c]);
}
if (!len){
if (!a && b && c){
cnt[len][a][b][c] = 1;
}else {
cnt[len][a][b][c] = 0;
}
s1[len][a][b][c] = s2[len][a][b][c] = 0;
return Bo(cnt[len][a][b][c], s1[len][a][b][c], s2[len][a][b][c]);
}
int Max = (fp ? bit[len] : 9);
lld vc = 0, vs1 = 0, vs2 = 0;
for (int i = 0; i <= Max; i++){
int nl = len - 1 , na = (a || i == 7), nb = (b + i) % 7, nc = (c * 10 + i) % 7;
Bo tmp = dfs(nl, na, nb, nc, i == Max && fp);
lld f = Fac[nl] * i % mod;
vc = (vc + tmp.cnt) % mod;
vs1 = (vs1 + tmp.s1 + tmp.cnt * f) % mod;
vs2 = (vs2 + tmp.s2 + (f * f) % mod * tmp.cnt + 2 * f * tmp.s1) % mod;
}
if (!fp){
cnt[len][a][b][c] = vc;
s1[len][a][b][c] = vs1;
s2[len][a][b][c] = vs2;
}
return Bo(vc, vs1, vs2);
}

lld solve(lld x){
lld tmp = x;
int len = 0;
while (tmp){
bit[++len] = tmp % 10;
tmp /= 10;
}
Bo res = dfs(len, 0, 0, 0, 1);
return res.s2 % mod;
}

void init(){
Fac[0] = 1;
for (int i = 1; i <= 18; i++){
Fac[i] = Fac[i-1] * 10 % mod;
}
memset(cnt, -1, sizeof(cnt));
}

int main(){
int T;
scanf("%d", &T); init();
for (int cas = 1; cas <= T; cas++){
lld l, r;
scanf("%I64d%I64d", &l, &r);
printf("%I64d\n", (solve(r) - solve(l - 1) + mod) % mod);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: