luogu P3245 [HNOI2016]大数

传送门

\(HNOI2019\)前最后一题了qwq

这题要分情况,如果\(p=2\)\(5\),那么只要区间内最后一个数字是\(p\)的倍数就好了,这个可以莫队,也有更优秀的做法.莫队做法可以看代码

否则,考虑一个数怎么表示,记\(s_i\)为前\(i\)为构成的数,可以知道区间\([i,j]\)的数应该是\(s_r-s_{l-1}*10^{r-l+1}\),现在要求这个数模\(p\)为0,那么也就是\[s_r-s_{l-1}*10^{r-l+1}\equiv0\ (\mathrm{mod}\ p)\]

两边同时除掉\(10^r\),得到

\[s_r*10^{-r}-s_{l-1}*10^{-(l-1)}\equiv0\ (\mathrm{mod}\ p)\]

如果位置\(i\)的权值为\(s_i*10^{-i}\),那么一个区间\([i,j]\)的答案就是\([i-1,j]\)中每种权值相同的点对个数,这个还是比较好写的

#include<bits/stdc++.h>
#define LL long long
#define db long double
#define il inline

using namespace std;
const int N=1e5+10;
il LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int p,a[N],n,sqt,q,be[N];
LL an[N],na;
char cc[N];
struct qu
{
    int l,r,i;
    bool operator < (const qu &bb) const {return be[l]!=be[bb.l]?l<bb.l:r<bb.r;}
}qq[N];
int fpow(int a,int b){a%=p;int an=1;while(b){if(b&1) an=1ll*an*a%p;a=1ll*a*a%p,b>>=1;} return an;}
namespace ct1
{
    int cn;
    void wk()
    {
        sort(qq+1,qq+q+1);
        for(int i=1,l=1,r=0;i<=q;++i)
        {
            while(r<qq[i].r) ++r,cn+=a[r]%p==0,na+=(a[r]%p==0?r-l+1:0);
            while(r>qq[i].r) na-=(a[r]%p==0?r-l+1:0),cn-=a[r]%p==0,--r;
            while(l<qq[i].l) na-=cn,cn-=a[l]%p==0,++l;
            while(l>qq[i].l) --l,cn+=a[l]%p==0,na+=cn;
            an[qq[i].i]=na;
        }
    }
}
namespace ct2
{
    int cn[N],b[N],m;
    void wk()
    {
        int pp=fpow(10,p-2);
        b[++m]=0;
        for(int i=1,j=1,sm=0;i<=n;++i)
        {
            sm=1ll*sm*10%p+a[i],j=1ll*j*pp%p;
            a[i]=1ll*sm*j%p;
            b[++m]=a[i];
        }
        sort(b+1,b+m+1),m=unique(b+1,b+m+1)-b-1;
        for(int i=0;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b;
        for(int i=1;i<=q;++i) --qq[i].l;
        sort(qq+1,qq+q+1);
        for(int i=1,l=0,r=-1;i<=q;++i)
        {
            while(r<qq[i].r) ++r,++cn[a[r]],na+=cn[a[r]]-1;
            while(r>qq[i].r) na-=cn[a[r]]-1,--cn[a[r]],--r;
            while(l<qq[i].l) na-=cn[a[l]]-1,--cn[a[l]],++l;
            while(l>qq[i].l) --l,++cn[a[l]],na+=cn[a[l]]-1;
            an[qq[i].i]=na;
        }
    }
}
    
int main()
{
    p=rd();
    scanf("%s",cc+1);
    n=strlen(cc+1);
    sqt=sqrt(n);
    for(int i=1;i<=n;++i) a[i]=cc[i]-'0',be[i]=i/sqt;
    q=rd();
    for(int i=1;i<=q;++i) qq[i].l=rd(),qq[i].r=rd(),qq[i].i=i;
    if(p==2||p==5) ct1::wk();
    else ct2::wk();
    for(int i=1;i<=q;++i) printf("%lld\n",an[i]);
    return 0; 
}

猜你喜欢

转载自www.cnblogs.com/smyjr/p/10659752.html