BZOJ4542: [Hnoi2016]大数

来源:互联网 发布:淘宝待揽件是什么意思 编辑:程序博客网 时间:2024/06/05 11:24

BZOJ4542: [Hnoi2016]大数

莫队·乱搞

题解:

蛤~我这种蒟蒻怎么可能自己想出来呢2333~
但是我看网上的题解很多没有证明过程,就写一下吧~

ans=i=lrj=ir1((10)nrk=ijs[i]10nkmodp==0)

num[i]=jk=is[i]10nk
因为p是素数,那么10=10p2

原式:

ans=i=lrj=ir1(10(p2)(nr)(num[i]num[j+1])modp==0)

如果p!=2&&p!=510tmodp肯定不为0。所以要想modp==0,则必有num[i]=num[j+1].

这样就转化成了一个区间中有多少对数相同,离散化一下,用莫队就可以了。

那么假如p==2||p==5呢?

我们发现一个数只要最后一位是2或5的倍数,不管前面是什么,它一定是。因此只考虑最后一位。

做两个前缀和,一个(A)记录前缀[1,i]中有多少子串是p的倍数,另一个(B)记录前缀[1,i]中有多少位是p的倍数。

ans=(A[r]A[l1])(B[r]B[l1])(l1)

(B[r]B[l1])(l1)就是开始在l前面,结束在[l,r]中的p的倍数子串的个数。

好神啊QwQ……

Code:

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endlusing namespace std;typedef long long ll;const int N = 100005;ll p,n,m,res,bsz;  char str[N];ll cnt[N],num[N],tp[N],ans[N],A[N],B[N]; struct Que{    ll l,r,id;    bool operator < (const Que &b) const {        return l/bsz < b.l/bsz || (l/bsz == b.l/bsz && r < b.r);    }} q[N];void insert(ll x){ res+=cnt[x]; cnt[x]++; }void erase(ll x){ cnt[x]--; res-=cnt[x]; }int main(){    freopen("a.in","r",stdin);    scanf("%lld%s%lld",&p,str+1,&m);     n=strlen(str+1);    if(p!=2 && p!=5){        ll base=1;        for(ll i=n;i>=1;i--){            base=base*10%p;            num[i]=(num[i+1]+(str[i]-'0')*base)%p;            tp[i]=num[i];        } tp[n+1]=num[n+1];        sort(tp+1,tp+2+n); ll tpsz=unique(tp+1,tp+2+n)-tp-1;        for(ll i=1;i<=n+1;i++){            num[i]=lower_bound(tp+1,tp+1+tpsz,num[i])-tp;        }        bsz=sqrt(n);        for(ll i=1;i<=m;i++){            scanf("%lld%lld",&q[i].l,&q[i].r);            q[i].id=i; q[i].r++;        }        sort(q+1,q+1+m);         ll lpos=1, rpos=0;        for(ll i=1;i<=m;i++){            while(lpos < q[i].l){ erase(num[lpos]); lpos++; }            while(lpos > q[i].l){ lpos--; insert(num[lpos]); }            while(rpos < q[i].r){ rpos++; insert(num[rpos]); }            while(rpos > q[i].r){ erase(num[rpos]); rpos--; }            ans[q[i].id]=res;        }        for(ll i=1;i<=m;i++) printf("%lld\n",ans[i]);    }    else{        for(ll i=1;i<=n;i++){             if((str[i]-'0')%p==0){ A[i]=A[i-1]+i; B[i]=B[i-1]+1; }            else{ A[i]=A[i-1]; B[i]=B[i-1]; }        }        ll l,r;        for(ll i=1;i<=m;i++){            scanf("%lld%lld",&l,&r);            printf("%lld\n",(A[r]-A[l-1])-(B[r]-B[l-1])*(l-1));        }    }}
原创粉丝点击