• [BZOJ4542] [Hnoi2016] 大数 (莫队)


    Description

      小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345
    。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也
    是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素
    数7的倍数。

    Input

      第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的
    子串S[fr…to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1…3]为 2
    13。N,M<=100000,P为素数

    Output

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

    Sample Input

    11
    121121
    3
    1 6
    1 5
    1 4

    Sample Output

    5
    3
    2
      //第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。

    HINT

    Source

      2016.4.19新加数据一组

    Solution

      把n个后缀组成的数字全部对p取模。

      若s[l] ~ s[n]的余数和s[r] ~ s[n]的余数相同,那么s[l] ~ s[r - 1]区间内的数字就是p的倍数(l < r)

      这里有例外:当p = 2或p = 5时不成立。

      然后这个题就变成经典莫队题了:给定一个序列,每次询问[l, r]内有多少对相同的数

      每一个余数i给一个计数器ba[i](需离散化),记录[l, r]中这个数出现了几次,区间长度±1时答案改变值为ba[i]。

      然后。。。原数据里没有p = 2或p = 5的情况。。。所以就没有然后了。然而BZOJ加了组数据

      p = 2或p = 5时,用两个数组分别表示[1, i]中2或5的倍数时有多少种情况及有多少个数末尾是2或5的倍数,用前缀和维护。这部分就很简单了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll sqn, lst[100005], cd[100005], ba[100005], ans[100005];
     5 struct query
     6 {
     7     ll id, l, r;
     8     bool operator < (const query &rhs) const
     9     {
    10         if(l / sqn == rhs.l / sqn) return r < rhs.r;
    11         return l / sqn < rhs.l / sqn;
    12     }
    13 }q[100005];
    14 char s[100005];
    15 map<ll, ll> Map;
    16 int main()
    17 {
    18     ll n, m, p, l = 1, r = 0, cur = 0, bt = 1;
    19     scanf("%lld%s%lld", &p, s + 1, &m);
    20     n = strlen(s + 1), sqn = (ll)sqrt(n * 1.0);
    21     if(p != 2 && p != 5)
    22     {
    23         for(ll i = n; i; i--)
    24         {
    25             bt = bt * 10 % p;
    26             lst[i] = (lst[i + 1] + (s[i] - 48) * bt) % p;
    27             cd[i] = lst[i];
    28         }
    29         sort(cd + 1, cd + n + 1);
    30         for(ll i = 1; i <= n + 1; i++)
    31             Map[cd[i]] = i;
    32         for(ll i = 1; i <= n + 1; i++)
    33             lst[i] = Map[lst[i]];
    34         for(ll i = 1; i <= m; i++)
    35         {
    36             scanf("%lld%lld", &q[i].l, &q[i].r);
    37             q[i].id = i, q[i].r++;
    38         }
    39         sort(q + 1, q + m + 1);
    40         for(ll i = 1; i <= m; i++)
    41         {
    42             while(r < q[i].r) cur += ba[lst[++r]]++;
    43             while(l > q[i].l) cur += ba[lst[--l]]++;
    44             while(l < q[i].l) cur -= --ba[lst[l++]];
    45             while(r > q[i].r) cur -= --ba[lst[r--]];
    46             ans[q[i].id] = cur;
    47         }
    48         for(ll i = 1; i <= m; i++)
    49             printf("%lld
    ", ans[i]);
    50     }
    51     else
    52     {
    53         for(ll i = 1; i <= n; i++)
    54             if(!((s[i] - 48) % p))
    55                 ba[i] = ba[i - 1] + 1, cd[i] = cd[i - 1] + i;
    56             else
    57                 ba[i] = ba[i - 1], cd[i] = cd[i - 1];
    58         for(ll i = 1; i <= m; i++)
    59         {
    60             scanf("%lld%lld", &l, &r);
    61             printf("%lld
    ", cd[r] - cd[l - 1] - (ba[r] - ba[l - 1]) * (l - 1));
    62         }
    63     }
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    mysql备份与binlog
    linux释放cached
    linux下mysql迁移到其他分区
    java分析jvm常用指令
    Mac下安装WebStrom
    Final
    Spring 复习
    ubuntu 14.4安装java环境
    php复习
    java 重难点
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5407753.html
Copyright © 2020-2023  润新知