Luogu 3245 大數

Luogu 3245 大數

  • 開始就想 \(10\) 進制 \(hash\) ,\(Hash(r)\equiv Hash(l-1)\cdot 10^{r-l+1}\) ,感受沒什麼美妙的性質啊...
  • 而後把 \(hash\) 換個方向,先加低位,再加高位,就成了 \(\frac {Hash(l)-Hash(r+1)} {10^{n-r}}\equiv 0\) ,彷佛,就很美妙了?
  • \(P\not=2,5\) 時,下面的分母有逆元,那麼只能是 \(Hash(l)\equiv Hash(r+1)\) ,就變成了在一段區間內問相同元素的對數,離散化以後,用莫隊能夠解決.
  • \(P=2,5\) 時,一段區間內僅有以 \(P,0\) 結尾的串符合條件,計數至關簡單.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=1e5+10;
int n,m,P;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
struct query
{
    int l,r,id,bel;
    bool operator < (const query &rhs) const
    {
        if(bel!=rhs.bel)
            return bel<rhs.bel;
        if(r!=rhs.r)
            return r<rhs.r;
        return l<rhs.l;
    }
}q[MAXN];
char buf[MAXN];
int Hash[MAXN],cp[MAXN];
int cnt[MAXN];
ll ans[MAXN],res;
void add(int x)
{
    res+=cnt[Hash[x]];
    ++cnt[Hash[x]];
}
void rem(int x)
{
    --cnt[Hash[x]];
    res-=cnt[Hash[x]];
}
int sumcnt[MAXN],sumpos[MAXN];
void solve_spj()
{
    for(int i=1;i<=n;++i)
    {
        if(buf[i]-'0'==0 || buf[i]-'0'==P)
            sumcnt[i]=1,sumpos[i]=i;
        sumcnt[i]+=sumcnt[i-1];
        sumpos[i]+=sumpos[i-1];
    }
    m=read();
    for(int i=1;i<=m;++i)
    {
        int l=read(),r=read();
        ll cntsum=sumcnt[r]-sumcnt[l-1],possum=sumpos[r]-sumpos[l-1];
        ll res=possum-1LL*(l-1)*cntsum;
        printf("%lld\n",res);
    }
}
int main()
{
    P=read();
    scanf("%s",buf+1);
    n=strlen(buf+1);
    if(P==2 || P==5)
    {
        solve_spj();
        return 0;
    }
    int pow10=1;
    for(int i=n;i>=1;--i)
    {
        cp[i]=Hash[i]=add(Hash[i+1],mul(buf[i]-'0',pow10));
        pow10=mul(pow10,10);
    }
    ++n;//0
    sort(cp+1,cp+1+n);
    int tot=unique(cp+1,cp+1+n)-cp-1;
    for(int i=1;i<=n;++i)
        Hash[i]=lower_bound(cp+1,cp+1+tot,Hash[i])-cp;
    m=read();
    int BlockSize=sqrt(m);
    for(int i=1;i<=m;++i)
    {
        q[i].l=read();
        q[i].r=read();
        q[i].id=i;
        q[i].bel=q[i].l/BlockSize;
    }
    sort(q+1,q+1+m);
    int L=1,R=0;
    for(int i=1;i<=m;++i)
    {
        int l=q[i].l,r=q[i].r;
        ++r;
        if(l==r)
            continue;
        while(R<r)
            add(++R);
        while(L<l)
            rem(L++);
        while(L>l)
            add(--L);
        while(R>r)
            rem(R--);
        ans[q[i].id]=res;
    }
    for(int i=1;i<=m;++i)
        printf("%lld\n",ans[i]);
    return 0;
}
相關文章
相關標籤/搜索