【数位DP】【P4127】[AHOI2009]同类分布

Description

给出两个数 \(a,~b\) 求出 \([a~,b]\) 中各位数字之和能整除原数的数的个数。

Limitations

\(1 \leq a,~b \leq 10^{18}\)

Solution

考虑数位DP。

设数字 \(A = \sum_{i = 0}^k a_i \times 10^i\),其数字和 \(B = \sum_{i = 0}^k a_i\)

那么 \(A\) 满足条件即为 \(A \equiv 0 \pmod B\),根据同余的性质,可以将求和符号拆开:

\[\sum_{i = 0}^k (a_i \times 10^i \bmod B)~\equiv~0\pmod B\]

考虑 \(B\) 事实上很小,在 \(18\) 位数字都是 \(9\) 的时候也不超过 \(200\),因此可以枚举 \(B\)。

设 \(f_{i, j, k}\) 位考虑前 \(i\) 位,前 \(i\) 位对应模 \(B\) 的值为 \(j\),且后面几位的数字和为 \(k\),不顶上界的方案数,转移时枚举当前这一位是几即可。

Code

// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>

const int maxn = 70;
const int maxm = 163;
const int maxt = 10;

int A[maxn], B[maxn];
ll frog[maxn][maxm][maxm];

int ReadNum(int *p);
ll calc(const int *const num, const int n);

int main() {
  freopen("1.in", "r", stdin);
  int x = ReadNum(A), y = ReadNum(B);
  ll _sum = 0, _val = 0, _ten = 1;
  for (int i = x - 1; ~i; --i) {
    _sum += A[i]; _val += A[i] * _ten;
    _ten *= 10;
  }
  qw(calc(B, y) - calc(A, x) + (!(_val % _sum)), '\n', true);
  return 0;
}

int ReadNum(int *p) {
  auto beg = p;
  do *p = IPT::GetChar() - '0'; while ((*p < 0) || (*p > 9));
  do *(++p) = IPT::GetChar() - '0'; while ((*p <= 9) && (*p >= 0));
  return p - beg;
}

ll calc(const int *const num, const int n) {
  int dn = n - 1;
  if (n <= 1) { return num[0]; }
  ll _ret = 0, _ten = 1;
  for (int i = 1; i < n; ++i) _ten *= 10;
  for (int p = 1; p < maxm; ++p) {
    memset(frog, 0, sizeof frog);
    ll ten = _ten; int tm = ten % p;
    int upc = num[0] * tm % p, left = p - num[0];
    for (int i = 1; i < num[0]; ++i) if (p >= i) {
      frog[0][i * tm % p][p - i] = 1;
    }
    for (int i = 1; i < n; ++i) {
      int di = i - 1;
      tm = (ten /= 10) % p;
      for (int j = 0; j < p; ++j) {
        for (int k = 0; k < p; ++k) {
          for (int h = 0; h < 10; ++h) if ((h + k) <= p) {
            int dh = h * tm % p, dj = j >= dh ? j - dh : j - dh + p;
            frog[i][j][k] += frog[di][dj][k + h];
          }
        }
      }
      for (int j = 1; j < 10; ++j) if (j <= p) {
        ++frog[i][j * tm % p][p - j];
      }
      for (int h = 0; h < num[i]; ++h) if (h <= left) {
        int dh = h * tm % p;
        ++frog[i][(upc + dh) % p][left - h];
      }
      upc = (upc + num[i] * tm) % p; left -= num[i];
    }
    _ret += frog[dn][0][0];
    if ((upc == 0) && (left == 0)) ++_ret;
  }
  return _ret;
}

Summary

逐字符读入 \(L\) 时,\(L - 1\) 并不方便处理,不如改成 \([1, R] - [1,L] + (L\)是否合法\()\)。

原文地址:https://www.cnblogs.com/yifusuyi/p/11403336.html

时间: 2024-11-03 17:59:12

【数位DP】【P4127】[AHOI2009]同类分布的相关文章

P4127 [AHOI2009]同类分布

链接:https://www.luogu.org/problemnew/show/P4127 题目描述 给出两个数 a,ba,b ,求出 [a,b][a,b] 中各位数字之和能整除原数的数的个数. 输入输出格式 输入格式: 一行,两个整数 aa 和 bb 输出格式: 一个整数,表示答案 输入输出样例 输入样例#1: 复制 10 19 输出样例#1: 复制 3 说明 对于所有的数据, 1 ≤ a ≤ b ≤ 10^18 题解:数位dp, 但有一个问题,我们不知道各个数位数字之和:18*9是很小的,

[AHOI2009]同类分布

[AHOI2009]同类分布 求区间\([l,r]\)内的数,满足自己能整除自己各个数位上的和的数的个数,\(l,r\leq 10^{18}\). 解 不难得知设\(f_n\)为n以内的满足条件的数,答案即\(f_r-f_l\),因为递推中要表现整除,可以考虑摸递推. 要表现各个数位的和,又要变现长度,而且还要表现摸数,还有余数,故设\(f[i][j][k][l]\)表示i位的数,各数位的和为j,摸数为k,余数为l的数的方案数,因此不难有 \[f[i][j][k][l]=\sum_{p=0}^9

[luogu4127 AHOI2009] 同类分布 (数位dp)

传送门 Solution 裸数位dp,空间存不下只能枚举数字具体是什么 注意memset最好为-1,不要是0,有很多状态答案为0 Code //By Menteur_Hxy #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define Re registe

【题解】AHOI2009同类分布

好开心呀~果然只有不看题解做出来的题目才会真正的有一种骄傲与满足吧ヾ(????)?" 实际上这题只要顺藤摸瓜就可以了.首先按照数位dp的套路,有两维想必是省不掉:1.当前dp到到的位数:2.0/1状态表示是否受限制(这一条是因为有数字上限).然后根据这两个维度来接着往下想.第二个维度先撇开不看,我们只考虑如何从第 \(i - 1\) 位dp到第 \(i\) 位.在这里其实卡了有点久,因为如果除数与被除数都在改变,那么两维的转移是非常凉凉的. 这个时候联想题目的特殊性质 ----- 当感觉无法优化

【一天一DP计划】数位dp

入坑之好博 一本通 数位DP 浅谈数位DP ## P4127 同类分布 现在关键的问题是:怎样记录dp状态? 这里 st可达到 1e18 显然是不能作为dp转移的下标直接记录的 所以我们考虑取模 我们最理想的模数当然是把每次搜到最后得到的数字各个位数之和 但是我们发现在这个过程中 sum是发生变化的 所以我们就应该以一个定值作为模数 那好,我们虽然不知道最后各位之和的结果,我们枚举总可以吧 我们只需要枚举所有的各位数字之和作为模数 最后判断 sum 和枚举的 mod相等并且 st%sum=0 的

手打AC的第2道数位DP:BZOJ1799: [Ahoi2009]self 同类分布

先讲下个人对于数位DP的看法吧... 挺难理解的 首先需要明白的一点:前缀和很重要 其次:必须用到记忆化搜索(本人蒟蒻,必须要用这种方法降低难度) 然后呢,需要判断约束的条件:(1.前缀0(有时需要,有时不需要):2.数位的取值(基本都需要)) 比如这道题,乍一看无思路,然后呢.... 就会出现很神奇的事情 大胆尝试(第一次)3维(题解本来是4维的...) 居然就XJB A了... 略显蛋疼... 回归正题*2: 本题的状态有些难找,但是由于数位最多的也只有pos,所以就可枚举所有的数位和...

BZOJ1799 self 同类分布 数位dp

BZOJ1799self 同类分布 题意 给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数. [约束条件]1 ≤ a ≤ b ≤ 10^18 题解 1.所有的位数之和<9*18=1622.所以,dp[i][j][k][m]表示有i位(允许有前导0),数位和为k,模数为m,前i位与模数的模为j的符合条件的数的个数.这样要炸空间,怎么办!!其实这个dp的最后一维可以省去,因为对于不同的m值,dp互不相干.这样还是要超时的,有5亿多.于是就要卡常数,具体见代码里面的枚举的上下界. 代码 #

BZOJ 1799 同类分布(数位DP)

给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数.1<=a<=b<=1e18. 注意到各位数字之和最大是153.考虑枚举这个东西.那么需要统计的是[0,a-1]和[0,b]内各位数字之和为x且能整除x的数字个数. 那么我们只需要数位dp一波即可. 令dp[pos][i][x]表示有pos位且数字之和为x的数mod P=i的数字个数. 则转移方程显然可得. # include <cstdio> # include <cstring> # include

bzoj 1799: [Ahoi2009]self 同类分布 题解

[原题] 1799: [Ahoi2009]self 同类分布 Time Limit: 50 Sec  Memory Limit: 64 MB Submit: 554  Solved: 194 [Submit][Status] Description 给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数. Input Output Sample Input 10 19 Sample Output 3 HINT [约束条件]1 ≤ a ≤ b ≤ 10^18 Source Day1 [分析]