zoukankan      html  css  js  c++  java
  • 【莫队】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个询问的答案。


    题目分析

    一个区间[l,r]产生贡献即$number_{i,j}equiv 0 ({ m mod} p)$.

    按照常见套路来说,应该把区间拆成关于端点的式子。用$pre[i]$表示前$i$位在十进制下的数值,那么即$number_{i,j}=pre[j]-10^{j-i+1}*pre[i-1]$。将式子移项发现左右两边形如$f(r)=f(l-1)$(据说这是一种经典的莫队套路)那么于此已经将区间问题转化为关于单点的可$O(1)$修改的子问题了。

    之后的操作就相对套路:将$n+1$个$f(i)$(不要忘记统计$f(0)$)预先离散化处理;然后常规莫队操作。

    注意莫队要先修改再更新!

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cctype>
      4 #include<cstring>
      5 #include<algorithm>
      6 const int maxn = 100035;
      7 
      8 int blk[maxn];
      9 struct QRs
     10 {
     11     int l,r,id;
     12     bool operator < (QRs a) const
     13     {
     14         if (blk[l]==blk[a.l]) return r < a.r;
     15         return blk[l] < blk[a.l];
     16     }
     17 }q[maxn];
     18 char s[maxn];
     19 int p,n,m,cnt,tot,size,inv10;
     20 int lbd,rbd,lSd[maxn],rSd[maxn];
     21 int ans[maxn],sum[maxn],pre[maxn],t[maxn];
     22 
     23 int read()
     24 {
     25     char ch = getchar();
     26     int num = 0;
     27     bool fl = 0;
     28     for (; !isdigit(ch); ch=getchar())
     29         if (ch=='-') fl = 1;
     30     for (; isdigit(ch); ch=getchar())
     31         num = (num<<1)+(num<<3)+ch-48;
     32     if (fl) num = -num;
     33     return num;
     34 }
     35 int qmi(int a, int b)
     36 {
     37     int ret = 1;
     38     while (b)
     39     {
     40         if (b&1) ret = 1ll*ret*a%p;
     41         b >>= 1, a = 1ll*a*a%p;
     42     }
     43     return ret;
     44 }
     45 void lAdd(int lbd)
     46 {
     47     rSd[sum[lbd]]++, tot+=rSd[sum[lbd-1]], lSd[sum[lbd-1]]++;
     48 }
     49 void rAdd(int rbd)
     50 {
     51     lSd[sum[rbd-1]]++, tot+=lSd[sum[rbd]], rSd[sum[rbd]]++;
     52 }
     53 void lErase(int lbd)
     54 {
     55     lSd[sum[lbd-1]]--, tot-=rSd[sum[lbd-1]], rSd[sum[lbd]]--;
     56 }
     57 void rErase(int rbd)
     58 {
     59     rSd[sum[rbd]]--, tot-=lSd[sum[rbd]], lSd[sum[rbd-1]]--;
     60 }
     61 int main()
     62 {
     63     freopen("bignum.in","r",stdin);
     64     freopen("bignum.out","w",stdout);
     65     p = read(), scanf("%s",s+1);
     66     n = strlen(s+1), size = sqrt(n+0.5)+5;
     67     if (p==2||p==5){
     68         for (int i=1; i<=n; i++)
     69         {
     70             ans[i] = ans[i-1], sum[i] = sum[i-1];
     71             if ((s[i]-'0')%p==0) ans[i]++, sum[i] += i;
     72         }
     73         m = read();
     74         for (int i=1; i<=m; i++)
     75         {
     76             int l = read(), r = read();
     77             printf("%d
    ",sum[r]-sum[l-1]-(ans[r]-ans[l-1])*(l-1));
     78         }
     79         return 0;
     80     }
     81     for (int i=1; i<=n; i++) blk[i] = i/size, pre[i] = (pre[i-1]*10ll%p+s[i]-'0')%p;
     82     inv10 = qmi(10, p-2);
     83     for (int i=0, pr=1; i<=n; i++)
     84         t[i] = sum[i] = 1ll*pre[i]*pr%p, pr = 1ll*pr*inv10%p;
     85     std::sort(t, t+n+1), cnt = std::unique(t, t+n+1)-t-1;
     86     for (int i=0; i<=n; i++)
     87         sum[i] = std::lower_bound(t, t+cnt+1, sum[i])-t+1;
     88     m = read();
     89     for (int i=1; i<=m; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
     90     std::sort(q+1, q+m+1);
     91     lbd = 1, rbd = 0;
     92     for (int i=1; i<=m; i++)
     93     {
     94         while (lbd < q[i].l) lErase(lbd++);
     95         while (lbd > q[i].l) lAdd(--lbd);
     96         while (rbd > q[i].r) rErase(rbd--);
     97         while (rbd < q[i].r) rAdd(++rbd);
     98         ans[q[i].id] = tot;
     99     }
    100     for (int i=1; i<=m; i++) printf("%d
    ",ans[i]);
    101     return 0;
    102 }

    END

  • 相关阅读:
    实例属性的读取与设置
    淘宝ued
    反射发出动态类型(下)
    iOS多线程的初步研究3
    C# 自动提交到百度ping服务
    .NET自带IOC
    Entity Framework返回IEnumerable还是IQueryable?
    ASP.NET MVC4简单使用ELMAH记录系统日志
    ASP.NET基础之HttpModule学习
    【Linux】Shell学习笔记之四——文件和目录管理(硬连接和软连接)
  • 原文地址:https://www.cnblogs.com/antiquality/p/9748670.html
Copyright © 2011-2022 走看看