bzoj 4542: [Hnoi2016]大数 (莫队)

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
//第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。
 
实现代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll M = 1e5 + ;
ll blo;
struct node{
ll id,l,r;
bool operator < (const node &k) const {
if(l/blo == k.l/blo) return r < k.r;
return l/blo < k.l/blo;
}
}q[M];
ll a[M],hs[M];
ll ba[M],ans[M];
char s[M];
map<ll,ll>mp; int main()
{
ll p,m,l=,r=;
scanf("%lld%s%lld",&p,s+,&m);
ll n = strlen(s+); blo = (ll)sqrt(n*1.0);
if(p != &&p != ){
ll num = ;
for(ll i = n;i >= ;i --){
a[i] = (a[i+]+(s[i]-)*num)%p;
num = num*%p;
hs[i] = a[i];
}
sort(hs+,hs++n);
ll siz = unique(hs+,hs++n)-hs-;
for(int i = ;i <= n+;i ++)
a[i] = lower_bound(hs+,hs++siz,a[i])-hs;
for(ll i = ;i <= m;i ++){
scanf("%lld%lld",&q[i].l,&q[i].r);
q[i].id = i; q[i].r ++;
}
sort(q+,q+m+);
ll cnt = ;
for(ll i = ;i <= m;i ++){
while(r < q[i].r) cnt += ba[a[++r]]++;
while(l > q[i].l) cnt += ba[a[--l]]++;
while(l < q[i].l) cnt -= --ba[a[l++]];
while(r > q[i].r) cnt -= --ba[a[r--]];
ans[q[i].id] = cnt;
}
for(ll i = ;i <= m;i ++)
printf("%lld\n",ans[i]);
}
else{
for(ll i = ;i <= n;i ++){
if(!((s[i]-)%p))
ba[i] = ba[i-]+,hs[i] = hs[i-]+i;
else
ba[i] = ba[i-],hs[i] = hs[i-];
}
for(ll i = ;i <= m;i ++){
scanf("%lld%lld",&l,&r);
printf("%lld\n",hs[r]-hs[l-]-(ba[r]-ba[l-])*(l-));
}
}
}
上一篇:Kickstart 自动化安装配置


下一篇:工具:BT Sync 同步文件