[bzoj4542][莫隊演算法]大數
阿新 • • 發佈:2018-12-15
Description
小 B 有一個很大的數 S,長度達到了 N 位;這個數可以看成是一個串,它可能有前導 0,例如00009312345
。小B還有一個素數P。現在,小 B 提出了 M 個詢問,每個詢問求 S 的一個子串中有多少子串是 P 的倍數(0 也 是P 的倍數)。例如
S為0077時,其子串 007有6個子串:0,0,7,00,07,007;顯然0077的子串007有6個子串都是素 數7的倍數。
Input
第一行一個整數:P。第二行一個串:S。第三行一個整數:M。接下來M行,每行兩個整數 fr,to,表示對S 的
子串S[fr…to]的一次詢問。注意:S的最左端的數字的位置序號為 1;例如S為213567,則S[1]為 2,S[1…3]為 2
13。N,M<=100000,P為素數
Output
輸出M行,每行一個整數,第 i行是第 i個詢問的答案。
Sample Input
11
121121
3
1 6
1 5
1 4
Sample Output
5
3
2
題解
求一下字尾和
不妨設 組成的數為 ,顯然
如果 ,在 下,顯然
於是這時候 即可
然後就是要求區間裡相同的數數量
離散化一下莫隊就行了…
的情況下,顯然只和最後一位有關…字首和搞搞即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const int MAXN=100010;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
LL stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(LL x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
int n,m;LL mod;
char ch[MAXN];
LL sum[MAXN];
struct LSnode{LL y,p;}nu[MAXN];
bool cmp1(LSnode n1,LSnode n2){return n1.y<n2.y;}
int rec[MAXN],cal[MAXN];
LL answer[MAXN],ans;
int pos[MAXN],block;
struct ask{int l,r,op;}w[MAXN];
bool cmp(ask n1,ask n2){return pos[n1.l]==pos[n2.l]?n1.r<n2.r:pos[n1.l]<pos[n2.l];}
LL pre[MAXN];
void up1(int now)
{
ans+=cal[rec[now]];
cal[rec[now]]++;
}
void up2(int now)
{
cal[rec[now]]--;
ans-=cal[rec[now]];
}
int s1[MAXN],s2[MAXN];
LL g1[MAXN],g2[MAXN];
int main()
{
mod=read();
scanf("%s",ch+1);
n=strlen(ch+1);block=sqrt(n+1);
pre[0]=1;for(int i=1;i<=MAXN-10;i++)pre[i]=pre[i-1]*10%mod;
for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
m=read();
for(int i=1;i<=m;i++)w[i].l=read(),w[i].r=read()+1,w[i].op=i;
for(int i=n;i>=1;i--)sum[i]=((ch[i]-'0')*pre[n-i]%mod+sum[i+1])%mod,nu[i].y=sum[i],nu[i].p=i;
sort(nu+1,nu+1+n,cmp1);
int tt=0;
for(int i=1;i<=n;i++)
{
if(nu[i].y!=nu[i-1].y)tt++;
rec[nu[i].p]=tt;
}
for(int i=1;i<=n;i++)
{
int num=ch[i]-'0';
s1[i]=s1[i-1]+(num%2==0);s2[i]=s2[i-1]+(num%5==0);
g1[i]=g1[i-1]+(num%2==0?i:0);
g2[i]=g2[i-1]+(num%5==0?i:0);
}
if(mod==2||mod==5)
{
for(int i=1;i<=m;i++)
{
LL aa;w[i].r--;
if(mod==5)aa=g2[w[i].r]-g2[w[i].l-1]-(LL)(w[i].l-1)*(s2[w[i].r]-s2[w[i].l-1]);
else aa=g1[w[i].r]-g1[w[i].l-1]-(LL)(w[i].l-1)*(s1[w[i].r]-s1[w[i].l-1]);
pr2(aa);
}
return 0;
}
sort(w+1,w+1+m,cmp);
for(int i=w[1].l;i<=w[1].r;i++)
{
ans+=cal[rec[i]];
cal[rec[i]]++;
}
int l=w[1].l,r=w[1].r;answer[w[1].op]=ans;
for(int i=2;i<=m;i++)
{
while(l>w[i].l)up1(--l);
while(l<w[i].l)up2(l++);
while(r>w[i].r)up2(r--);
while(r<w[i].r)up1(++r);
answer[w[i].op]=ans;
}
for(int i=1;i<=m;i++)pr2(answer[i]);
return 0;
}