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。
HINT
Source
Solution
把n个后缀组成的数字全部对p取模。
若s[l] ~ s[n]的余数和s[r] ~ s[n]的余数相同,那么s[l] ~ s[r - 1]区间内的数字就是p的倍数(l < r)
这里有例外:当p = 2或p = 5时不成立。
然后这个题就变成经典莫队题了:给定一个序列,每次询问[l, r]内有多少对相同的数
每一个余数i给一个计数器ba[i](需离散化),记录[l, r]中这个数出现了几次,区间长度±1时答案改变值为ba[i]。
然后。。。原数据里没有p = 2或p = 5的情况。。。所以就没有然后了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll sqn, lst[100005], cd[100005], ba[100005], ans[100005]; 5 struct query 6 { 7 ll id, l, r; 8 bool operator < (const query &rhs) const 9 { 10 if(l / sqn == rhs.l / sqn) return r < rhs.r; 11 return l / sqn < rhs.l / sqn; 12 } 13 }q[100005]; 14 char s[100005]; 15 map<ll, ll> Map; 16 int main() 17 { 18 ll n, m, p, l = 1, r = 0, cur = 0, bt = 1; 19 scanf("%lld%s%lld", &p, s + 1, &m); 20 n = strlen(s + 1), sqn = (ll)sqrt(n * 1.0); 21 for(ll i = n; i; i--) 22 { 23 bt = bt * 10 % p; 24 lst[i] = (lst[i + 1] + (s[i] - 48) * bt) % p; 25 cd[i] = lst[i]; 26 } 27 sort(cd + 1, cd + n + 1); 28 for(ll i = 1; i <= n + 1; i++) 29 Map[cd[i]] = i; 30 for(ll i = 1; i <= n + 1; i++) 31 lst[i] = Map[lst[i]]; 32 for(ll i = 1; i <= m; i++) 33 { 34 scanf("%lld%lld", &q[i].l, &q[i].r); 35 q[i].id = i, q[i].r++; 36 } 37 sort(q + 1, q + m + 1); 38 for(ll i = 1; i <= m; i++) 39 { 40 while(r < q[i].r) cur += ba[lst[++r]]++; 41 while(l > q[i].l) cur += ba[lst[--l]]++; 42 while(l < q[i].l) cur -= --ba[lst[l++]]; 43 while(r > q[i].r) cur -= --ba[lst[r--]]; 44 ans[q[i].id] = cur; 45 } 46 for(ll i = 1; i <= m; i++) 47 printf("%lld\n", ans[i]); 48 return 0; 49 }
时间: 2024-11-08 22:06:42