zoukankan      html  css  js  c++  java
  • Bzoj4542--Hnoi2016大数

    一开始想到过用莫队,没有想出来怎么去转移。。。

    事实上对于一个子串是p的倍数的串有一个性质,就是开头和结尾的后缀串的余数相同,这个还是好理解的。

    假设一个子串[l,r]数值为t,设t=xp,这个子串结尾对应的原串后缀[r+1,n]数值为t',设t'=y*p+r

    那么这个串开头对应原串的后缀[l,n]值为w=t*10^(n-r+1)+t'=(x*10^(n-r+1)+y)*p+r,显然w%p=r

    但是对于10的两个质因子2,5是不成立的,因为t*10^(n-r+1)%P=0

    那么我们对于2和5单独来处理,2,5的话就只要结尾是2,5的倍数的都可以就可以简单求解了

    代码: 

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    inline int read() {
        int ret=0,f=1;char c=getchar();
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
        return ret*f;
    }
    
    #define MAXN 100005
    #define MAXM 100005
    
    int P,n,m,bl[MAXN],qsz,hs[MAXN];
    char s[MAXN];LL te[MAXN],re[MAXN];
    struct que{
        int l,r,id;
    }q[MAXM];LL ans[MAXM];
    
    inline bool cmp(const que &a,const que &b) {
        return bl[a.l]==bl[b.l]?a.r<b.r:a.l<b.l;
    }
    
    int BS(int v) {
        int l=0,r=n,mid,ret;
        while(l<=r) {
            mid=l+r>>1;
            if(hs[mid]>=v) r=mid-1,ret=mid;
            else l=mid+1;
        }
        return ret;
    }
    
    int nl=1,nr=0,ap[MAXN];LL now;
    inline void Chg(int v,int p) {
        ap[v]+=p;now+=p>0?ap[v]-1:-ap[v];
    }
    
    int main() {
        P=read();
        scanf("%s",s+1);te[0]=1;
        n=strlen(s+1);qsz=sqrt(n);
        for(int i=1;i<=n;i++) bl[i]=i/qsz,te[i]=te[i-1]*10%P;
        m=read();
        for(int i=1;i<=m;i++) {
            q[i].l=read();q[i].r=read();
            q[i].id=i;
        }
        if(10%P) {
            sort(q+1,q+m+1,cmp);
            for(int i=n;i>0;i--) re[i]=(re[i+1]+(s[i]-'0')*te[n-i])%P,hs[i]=re[i];
            sort(hs+1,hs+1+n);
            for(int i=n;i>0;i--) re[i]=BS(re[i]);
            for(int i=1;i<=m;i++) {
                q[i].r++;
                while(q[i].r>nr) Chg(re[++nr],1);
                while(q[i].l<nl) Chg(re[--nl],1);
                while(q[i].l>nl) Chg(re[nl++],-1);
                while(q[i].r<nr) Chg(re[nr--],-1);
                ans[q[i].id]=now;
            }
        }
        else {
            for(int i=n;i>0;i--) if((s[i]-'0')%P==0) re[i]=i,ap[i]=1;
            for(int i=1;i<=n;i++) re[i]+=re[i-1],ap[i]+=ap[i-1];
            for(int i=1;i<=m;i++) 
                ans[i]=re[q[i].r]-re[q[i].l-1]-(LL)(ap[q[i].r]-ap[q[i].l-1])*(q[i].l-1);
        }
        for(int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    日期多选插件Kalendae.js
    解决iReport打不开的一种方法
    Hibernate不能建表的问题
    【JAVA】虚拟机指令集
    解决jquery操作checkbox火狐下第二次无法勾选问题
    关于Java异常一段很有意思的代码
    C#中Winform程序中如何实现多维表头【不通过第三方报表程序】
    【转】C#中WinForm程序退出方法技巧总结
    为CentOS安装yum源
    Rsync CentOS 7 下安装
  • 原文地址:https://www.cnblogs.com/ihopenot/p/5995587.html
Copyright © 2011-2022 走看看