您的位置:首页 > 其它

HDU 4507 吉哥系列故事——恨7不成妻 数位DP

2014-08-03 14:12 330 查看
这个不是求的数量,而是求平方和,所以记忆化的时候不能像以前那样无脑的来。

先来看简单的情况,如果是求和,应该怎么搞。

假如我现在搜索到第3位,一共有5位,情况应该是这样的XXiXX,注意后面的X和前面的X都是不确定的,转移的时候应该是i * 10^(5-3) * (能满足的条件的数的数量) + sigma((每个分支下面满足条件的数量)* (分支和))这样的形式,然后再返回到上一层。这样子就可以记忆化了。但是除了要统计数量,还要统计和。

那么这里要统计平方和的话,如果还是上面这种情况,根据(a + b)^2 = a^2 + 2*a*b + b^2可以得出(i * 10^(5 - 3))^2 * (能满足的条件的数的数量) + 2 * sigma((每个分支下面满足条件的数量)*(分支和)) + sigma(分支平方和)。所以出了要维护分支和,还要维护分支平方和和数量。

真鬼畜

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <list>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 20;
const LL MOD = 1e9 + 7;
int lim[maxn],len = 0;
LL p10[maxn] = {1};

struct EE {
LL sqsum,sum,cnt;
bool vis;
EE(LL sqsum = 0,LL sum = 0,LL cnt = 0):sqsum(sqsum),sum(sum),cnt(cnt),vis(0) {}
};

EE f[maxn][10][10];

void getlim(LL num) {
len = 0;
memset(lim,0,sizeof(lim));
while(num) {
lim[len++] = num % 10;
num /= 10;
}
}

EE dfs(int now,int bitsum,int rest,int bound,LL num) {
if(now == 0) {
if(bitsum % 7 == 0 || rest % 7 == 0) return EE(0,0,0);
return EE(0,0,1);
}
EE ¬e = f[now][bitsum][rest];
if(note.vis && !bound) return note;
int m = bound ? lim[now - 1] : 9;
EE ret(0,0,0);
for(int i = 0;i <= m;i++) {
if(i == 7) continue;
int nbitsum = (bitsum + i) % 7;
int nrest = (rest * 10 + i) % 7;
int nbound = (i == m && bound);
EE nret = dfs(now - 1,nbitsum,nrest,nbound,num * 10 + i);
LL ff = p10[now - 1] * i % MOD;
ret.cnt = (nret.cnt + ret.cnt) % MOD;
ret.sum = ((nret.cnt * ff % MOD + nret.sum) % MOD + ret.sum) % MOD;
ret.sqsum = ((nret.cnt * ff % MOD * ff % MOD + nret.sqsum) % MOD + 2 * ff % MOD * nret.sum % MOD + ret.sqsum) % MOD ;
}
if(!bound) note = ret,note.vis = true;
return ret;
}

LL work(LL num) {
for(int i = 0;i < maxn;i++) {
for(int j = 0;j < 10;j++) {
for(int k = 0;k < 10;k++) {
f[i][j][k] = EE();
}
}
}
getlim(num);
EE ret = dfs(len,0,0,1,0);
return ret.sqsum;
}

int main() {
for(int i = 1;i < maxn;i++) p10[i] = p10[i - 1] * 10;
int T; cin >> T;
LL n,m;
while(T--) {
cin >> n >> m;
cout << (work(m) - work(n - 1) + MOD) % MOD << endl;
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: