zoukankan      html  css  js  c++  java
  • 【HNOI 2016】大数

    Problem

    Description

    小 B 有一个很大的数 (S),长度达到了 (N) 位;这个数可以看成是一个串,它可能有前导 (0),例如 00009312345 。小 B 还有一个素数 (P)

    现在,小 B 提出了 (M) 个询问,每个询问求 (S) 的一个子串中有多少子串是 (P) 的倍数((0) 也是 (P) 的倍数)。例如 (S)0077 时,其子串 007 有六个子串:0, 0, 7, 00, 07, 007;显然 0077 的子串 077 的六个子串都是素数 (7) 的倍数。

    Input Format

    第一行一个整数:(P)

    第二行一个串:(S)

    第三行一个整数:(M)

    接下来 (M) 行,每行两个整数 ( ext{fr}, ext{to}),表示对 (S) 的子串 (S[ ext{fr} ldots ext {to}]) 的一次询问。

    注意:(S) 的最左端的数字的位置序号为 (1);例如 (S)(213567),则 (S[1])(2)(S[1 ldots 3])(213)

    Output Format

    输出 (M) 行,每行一个整数,第 (i) 行是第 (i) 个询问的答案。

    Sample

    Input

    11
    121121
    3
    1 6
    1 5
    1 4
    

    Output

    5
    3
    2
    

    Explanation

    Explanation for Input

    第一个询问问的是整个串,满足条件的子串分别有:121121211211121121

    Range

    对于所有的数据,(N,M leq 100000)(P) 为素数。

    Algorithm

    莫队

    Mentality

    (......) 比较送分的题目。

    支持 (nlog) 的数据范围,可离线的区间询问,且问的内容一看就可以莫队 = = 。

    我们发现,设 (r[i])([i,n]) 组成的数,那么有:

    [num(i,j)=frac{(r[i]-r[j+1])}{10^{n-j}} ]

    我们把分母移到左边去,那么便有:

    [num(i,j)cdot 10^{n-j}=r[i]-r[j+1]\ num(i,j)cdot 10^{n-j} mod P=(r[i]-r[j+1]) mod P \ num(i,j)cdot 10^{n-j} mod P=r[i] mod P-r[j+1] mod P ]

    那么,当 (r[i])(r[j+1])(P) 取模的余数相同,那等式就必定等于 (0) ,则有:

    [num(i,j)cdot 10^{n-j} mod P=0 ]

    那么当 (10^{n-j} mod P eq 0) 时,因为最后的结果为 (0) ,所以必有 (num(i,j) mod P=0)

    也就是说,当 (P eq 2,5) 时,(num(i,j))(P) 的倍数当且仅当 (r[i])(r[j+1]) 关于模数 (P) 同余。

    那么我们的问题就变成了一个区间内有多少属性相同的点对了,这个就很莫队了。

    至于 (P=2,5) 的时候,特判处理即可。我们可以直接通过判断一个数的末位来判断这个数是否为 (P) 的倍数,我们可以直接记前缀和哇。

    Code

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    int n, m, mod, size, rest[100002], L, R, cnt, now[100001], ano[10][100001],
        sum[100001];
    char S[100001];
    long long ans, answer[100001], q[100001];
    struct Que {
      int l, r, q, d;
    } k[100001];
    struct node {
      int d, rest;
    } ls[100002];
    bool cmp(Que a, Que b) { return a.q == b.q ? a.r < b.r : a.q < b.q; }
    bool cmp2(node a, node b) { return a.rest < b.rest; }
    void Del(int x) { ans -= --now[rest[x]]; }
    void Add(int x) { ans += now[rest[x]]++; }
    int main() {
      cin >> mod >> S >> m;
      n = strlen(S);
      size = sqrt(n);
      for (int i = 1; i <= m; i++) {
        scanf("%d%d", &k[i].l, &k[i].r);
        k[i].q = k[i].l / size;
        k[i].r++;
        k[i].d = i;
      }
      if (mod == 2 || mod == 5) {
        for (int i = n; i > 0; i--) {
          sum[i] = sum[i + 1];
          if ((S[i - 1] - '0') % mod == 0) sum[i]++;
        }  //记录后缀中有多少个数是合法末位
        for (int i = n; i > 0; i--)
          q[i] =
              sum[i] + q[i + 1];  //记录后缀的后缀和,也就是后缀中有多少合法的区间
        for (int i = 1; i <= m; i++)
          printf(
              "%lld
    ",
              q[k[i].l] - q[k[i].r] -
                  (k[i].r - k[i].l) *
                      sum[k[i].r]);  //计算答案:区间的后缀和相减,再减去区间之外的末位对区间的贡献
        return 0;
      }
      sort(k + 1, k + m + 1, cmp);
      for (int i = 1; i <= 9; i++) {
        ano[i][1] = i % mod;
        for (int j = 2; j <= n; j++)
          ano[i][j] =
              1ll * ano[i][j - 1] * 10 % mod;  //计算每个数作为第 j 位时在 %P 下的值
      }
      for (int i = n; i >= 1; i--) {
        ls[i].rest = (ls[i + 1].rest + ano[S[i - 1] - '0'][n - i + 1]) %
                     mod;  //记录每个 r[i] 的 %P 之后的值
        ls[i].d = i;
      }
      sort(ls + 1, ls + n + 1, cmp2);
      for (int i = 1; i <= n; i++) {
        if (ls[i].rest > ls[i - 1].rest) cnt++;
        rest[ls[i].d] = cnt;
      }  //将余数离散化才能存
      L = k[1].l, R = k[1].l - 1;
      for (int i = 1; i <= m; i++) {
        while (L < k[i].l) Del(L++);
        while (L > k[i].l) Add(--L);
        while (R < k[i].r) Add(++R);
        while (R > k[i].r) Del(R--);
        answer[k[i].d] = ans;
      }
      for (int i = 1; i <= m; i++) printf("%lld
    ", answer[i]);
    }
    
    
  • 相关阅读:
    PyQt5库结构
    PyQt5
    QObject
    os.listdir()
    os.getcwd()
    os.chdir()
    os.access()
    __name__
    php 学习笔记之关于时区的那点事
    php 学习笔记之搭建开发环境(mac版)
  • 原文地址:https://www.cnblogs.com/luoshuitianyi/p/10644943.html
Copyright © 2011-2022 走看看