吉哥系列故事——恨7不成妻(数位 DP)

吉哥系列故事——恨7不成妻

∑ i = 1 n ( p r e + s u c ) 2 ∑ i = 1 n p r e 2 + s u c 2 + 2 × p r e × s u c n × p r e 2 + ∑ s u c 2 + 2 × p r e ∑ s u c \sum_{i = 1} ^{n}(pre + suc) ^ 2\\ \sum_{i = 1} ^{n} pre ^ 2 + suc ^ 2 + 2 \times pre \times suc\\ n \times pre ^ 2 + \sum suc ^ 2 + 2 \times pre \sum suc\\ i=1n(pre+suc)2i=1npre2+suc2+2×pre×sucn×pre2+suc2+2×presuc
所以考虑维护 c n t , s u m , s u m 2 cnt, sum, sum ^ 2 cnt,sum,sum2即可。

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;

inline int add(int x, int y) {
  return x + y < mod ? x + y : x + y - mod;
}

inline int sub(int x, int y) {
  return x >= y ? x - y : x - y + mod;
}

struct Res {
  int cnt, sum1, sum2;
}f[20][10][10];

int num[20], p[20], cnt;

Res dfs(int pos, int sum, int remain, int flag) {
  if (!pos) {
    if (sum != 0 && remain != 0) {
      return {1, 0, 0};
    }
    else {
      return {0, 0, 0};
    }
  }
  if (!flag && f[pos][sum][remain].cnt != -1) {
    return f[pos][sum][remain];
  }
  Res ans = {0, 0, 0};
  int nex = flag ? num[pos] : 9;
  for (int i = 0; i <= nex; i++) {
    if (i == 7) {
      continue;
    }
    Res cur = dfs(pos - 1, (sum + i) % 7, (remain * 10 + i) % 7, i == nex && flag);
    ans.cnt = add(ans.cnt, cur.cnt);
    int s = 1ll * i * p[pos] % mod;
    ans.sum1 = add(ans.sum1, add(1ll * s * cur.cnt % mod, cur.sum1));
    ans.sum2 = add(add(ans.sum2, 1ll * cur.cnt * s % mod * s % mod), add(cur.sum2, 2ll * s % mod * cur.sum1 % mod));
  }
  if (!flag) {
    f[pos][sum][remain] = ans;
  }
  return ans;
}

int calc(long long x) {
  cnt = 0;
  while (x) {
    num[++cnt] = x % 10;
    x /= 10;
  }
  return dfs(cnt, 0, 0, 1).sum2;
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  for (int i = 0; i < 20; i++) {
    for (int j = 0; j < 10; j++) {
      for (int k = 0; k < 10; k++) {
        f[i][j][k].cnt = -1;
      }
    }
  }
  p[1] = 1;
  for (int i = 2; i < 20; i++) {
    p[i] = 1ll * p[i - 1] * 10 % mod;
  }
  int T;
  scanf("%d", &T);
  while (T--) {
    long long l, r;
    scanf("%lld %lld", &l, &r);
    printf("%lld\n", sub(calc(r), calc(l - 1)));
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值