zoukankan      html  css  js  c++  java
  • bzoj 4542: [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的倍数。

    solution

    正解:莫队
    知道结论还是比较容易的,但是细节贼多啊.
    首先 (p) 是质数,所以满足结论:如果 (s[i-n]\%p=s[k-n]\%p),那么 (s[i-k]) 满足是 (p) 的倍数
    第一个细节就是,特判 (p=2,p=5),这个时候结论不成立
    然后就变成了查找区间内相同的数两两配对的方案数,莫队解决即可,另外这个模数没有给范围,实际上很大,需要离散化

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int n,m,block;char s[N];ll mod;
    namespace solve1{
      ll sum[N],c[N];
      void main(){
        for(int i=1;i<=n;i++){
          sum[i]=sum[i-1],c[i]=c[i-1];
          if((s[i]-'0')%mod==0)sum[i]+=i,c[i]++;
        }
        int m,x,y;cin>>m;
        while(m--){
          scanf("%d%d",&x,&y);
          printf("%lld
    ",(sum[y]-sum[x-1])-(x-1)*(c[y]-c[x-1]));
        }
      }
    }
    struct node{
      int l,r,b,id;
      bool operator <(const node &pr)const{
        if(b!=pr.b)return b<pr.b;
        return r<pr.r;
      }
    }q[N];
    ll v[N],t[N],b[N];ll ans[N],ret=0;
    inline void add(int x){ret+=t[v[x]];t[v[x]]++;}
    inline void delet(int x){t[v[x]]--;ret-=t[v[x]];}
    void solve(){
      scanf("%d",&m);
      for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].r++;q[i].id=i;
        q[i].b=q[i].l/block;
      }
      sort(q+1,q+m+1);
      ll str=0,tot=1;
      for(int i=n;i>=1;i--){
        str+=tot*(s[i]-48);str%=mod;
        tot*=10;tot%=mod;
        v[i]=b[i]=str;
      }
      b[0]=0;
      sort(b,b+n+1);
      int to=unique(b,b+n+1)-b-1;
      for(int i=1;i<=n+1;i++)v[i]=lower_bound(b,b+to+1,v[i])-b;
      int l=1,r=0;
      for(int i=1;i<=m;i++){
        while(r<q[i].r)r++,add(r);
        while(l>q[i].l)l--,add(l);
        while(r>q[i].r)delet(r),r--;
        while(l<q[i].l)delet(l),l++;
        ans[q[i].id]=ret;
      }
      for(int i=1;i<=m;i++)printf("%lld
    ",ans[i]);
    }
    void work()
    {
      scanf("%lld%s",&mod,s+1);
      n=strlen(s+1);block=sqrt(n);
      if(mod==2 || mod==5)solve1::main();
      else solve();
    }
    
    int main()
    {
      work();
      return 0;
    }
    
    
  • 相关阅读:
    config Doku wiki
    [转载]【python】ipython与python的区别
    数组和指针
    C++初始化数据成员
    RSA算法原理
    C++四种cast
    百度笔试准备2
    百度笔试准备1
    百度面试准备
    C++的空类中默认产生哪些类成员函数
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7957215.html
Copyright © 2011-2022 走看看