【題解】HNOI-2016大數

Problem

abandon_bzoj

Solution

不知道爲啥,我看到這題就覺得是莫隊,所以就沒怎多想,就那麼做了

考慮一個大數p|A ,那麼顯然p|A10x,xN

所以可以預處理f[i] 表示從第i 開始直到末尾所組成的大數modp 的值,那麼對於一個大數a[lr] 如果模p 爲零,則f[i]f[j+1]=0 ,題目轉化成了統計一段區間中相同的數字有多少對,那麼這題就成了一個很經典的莫隊問題了

接下來考慮怎麼求f[] 數組,考慮到同餘的可乘性,

g[x]=10xmodp
g[x]=g[x+1]10modp

進而得到f[i]=(a[i]g[i]+f[i+1])modp

Tips:在p25 時要特判

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>0?(x):(-(x)))

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=100100;
struct Query{int l,r,id;}qu[N];
char S[N];int s[N],a[N],hash[N],b[N];
ll Ans[N];
int n,m;ll p;

inline int cmp1(const Query&aa,const Query&bb){return aa.l<bb.l;}

inline int cmp2(const Query&aa,const Query&bb){return aa.r<bb.r;}

/*struct HASH{
    static const int P=1234547;
    int hs[P],val[P],nxt[P];
    char bo[P];
    HASH(){cl(val),cl(hs),cl(bo),cl(nxt);}
    int * operator [] (int x){
        int mo=x%P;
        rg int pp=hs[x];
        while(val[pp]!=x&&nxt[pp])pp=nxt[pp];
        if(val[pp]==x)return li[pp];
        nxt[pp]=hs[x];
    }
}hash;*/

void init();

void div_block();

void Unique();

void Print();

void pre_a(){
    int f=1%p;
    for(rg int i=n;i;--i){
        a[i]=1ll*(a[i+1]+f*s[i]%p)%p;
        f=1ll*f*10%p;
    }
    return ;
}

void Captain_Mo(){
    rg int l=1,r=0;ll ans=0;
    for(rg int i=1;i<=m;++i){
        ++qu[i].r;
        while(r<qu[i].r){++r;ans+=(hash[a[r]]++);}
        while(qu[i].l<l){--l;ans+=(hash[a[l]]++);}
        while(l<qu[i].l){ans-=(--hash[a[l]]);++l;}
        while(qu[i].r<r){ans-=(--hash[a[r]]);--r;}
        Ans[qu[i].id]=ans;
    }
    return ;
}

void solve_alone(){
    for(rg int i=1;i<=n;++i){
        Ans[i]=Ans[i-1],a[i]=a[i-1];
        if(s[i]%p==0)Ans[i]+=i,++a[i];
    }
    for(rg int i=1;i<=m;++i)
    printf("%lld\n",Ans[qu[i].r]-Ans[qu[i].l-1]-(a[qu[i].r]-a[qu[i].l-1])*(qu[i].l-1));
    return ;
}

int main(){
    init();if(p==2||p==5){solve_alone();return 0;}
    pre_a();
    div_block();
    Unique();
    Captain_Mo();
    Print();
    return 0;
}

void Print(){for(rg int i=1;i<=m;++i)printf("%lld\n",Ans[i]);return ;}

void Unique(){
    for(rg int i=1;i<=n;++i)b[i]=a[i];
    sort(b+1,b+n+2);
    int len=unique(b+1,b+n+2)-b-1;
    for(rg int i=1;i<=n;++i)
        a[i]=lower_bound(b+1,b+len+1,a[i])-b-1;
    return ;
}

void div_block(){
    sort(qu+1,qu+m+1,cmp1);
    int block=sqrt(1.0*m);
    for(rg int i=1;i<=m;i+=block)
        sort(qu+i,qu+min(i+block,m),cmp2);
    return ;
}

void init(){
    read(p);
    scanf("%s",S);
    for(rg int i=0;S[i];++i)
        s[++n]=S[i]-'0';
    read(m);
    for(rg int i=1;i<=m;++i)
        read(qu[i].l),read(qu[i].r),qu[i].id=i;
    return ;
}
發佈了100 篇原創文章 · 獲贊 49 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章