1. 程式人生 > >BZOJ4542: [Hnoi2016]大數

BZOJ4542: [Hnoi2016]大數

sin urn span include 第一個 註意 現在 getc scan

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

2016.4.19新加數據一組

Solution

設$num_i$ 表示 $[i...n]$的數

則$[l...r]$的數為$p$的倍數時有$\frac{num_{l-1}-num_{r}}{10^{r-l+1}}\space mod\space p = 0$

因為$p$為質數,所以$10^{r-l+1}$與$p$互質,即$num_{l-1}\equiv num_{r}(mod\space p)$

離散化num,用莫隊統計答案即可

#include <bits/stdc++.h>

#define ll long long
#define inf 0x3f3f3f3f
#define il inline

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar(‘\n‘)

    #define
I_int int inline I_int read() { I_int x = 0 , f = 1 ; char c = getchar() ; while( c < 0 || c > 9 ) { if( c == - ) f = -1 ; c = getchar() ; } while( c >= 0 && c <= 9 ) { x = x * 10 + c - 0 ; c = getchar() ; } return x * f ; } char F[ 200 ] ; inline void write( I_int x ) { if( x == 0 ) { putchar( 0 ) ; return ; } I_int tmp = x > 0 ? x : -x ; if( x < 0 ) putchar( - ) ; int cnt = 0 ; while( tmp > 0 ) { F[ cnt ++ ] = tmp % 10 + 0 ; tmp /= 10 ; } while( cnt > 0 ) putchar( F[ -- cnt ] ) ; } #undef I_int } using namespace io ; using namespace std ; #define N 100010 int cnt[N] , rnk[N] ; ll Ans[N] ; ll sum1[N] , sum2[N] , P , ans ; char s[N] ; int block ; struct node { int l , r , id ; } a[N] ; struct date { ll val ; int id ; } data[N] ; bool cmp(node a , node b) { return a.l / block == b.l / block ? a.r < b.r : a.l < b.l ; } bool cmp2(date a , date b) { return a.val < b.val ; } /* num_i 表示 [i...n]的數 \則[l...r]的數為p的倍數時有 \frac{num_{l-1}-num_{r}}{10^{r-l+1}}\space mod\space p = 0 \因為p為質數,所以10^{r-l+1}與p互質,即num_{l-1}\equiv num_{r}(mod\space p) \*/ void add(int x) { ans += cnt[rnk[x]] ++ ; } void del(int x) { ans -= -- cnt[rnk[x]] ; } int main() { int p = read() ; scanf("%s" , s + 1) ; int n = strlen(s + 1) , m = read() ; if(p == 2 || p == 5) { for(int i = 1 ; i <= n ; i ++) { sum1[i] = sum1[i - 1] ; sum2[i] = sum2[i - 1] ; if((s[i] - 0) % p == 0) sum1[i] ++ , sum2[i] += i; } for(int i = 1 ; i <= m ; i ++) { int l = read() , r = read() ; printf("%lld\n" , sum2[r] - sum2[l - 1] - (sum1[r] - sum1[l - 1])*(l - 1)) ; } return 0 ; } P = 1 ; for(int i = 1 ; i <= m ; i ++) a[i] = (node) {read() , read() + 1, i} ; block = sqrt(n) ; sort(a + 1 , a + m + 1 , cmp) ; for(int i = n ; i ; i --) P = P * 10 % p , data[i] = (date) {((s[i] - 0) * P % p + data[i+1].val) % p, i} ; sort(data + 1 , data + n + 1 , cmp2) ; for(int i = 1 ; i <= n + 1 ; i ++) { if(data[i].val == data[i-1].val) rnk[data[i].id] = rnk[data[i-1].id] ; else rnk[data[i].id] = i ; } int l = 1 , r = 0 ; for(int i = 1 ; i <= m ; i ++) { int ql = a[i].l , qr = a[i].r ; while(l < ql) del(l++) ; while(l > ql) add(--l) ; while(r > qr) del(r--) ; while(r < qr) add(++r) ; Ans[ a[i].id ] = ans ; } for(int i = 1 ; i <= m ; i ++) printf("%lld\n",Ans[i]) ; return 0 ; }

BZOJ4542: [Hnoi2016]大數