• loj #2053 莫队


    (des)
    存在一个长度为 (n) 的数字 (s), 一个素数 (P)
    (m) 次询问一段区间 ([l, r]) 内的子串构成的数是 (P) 的倍数

    (sol)
    对于一次询问 ([l, r])
    答案为

    [sum_{i=l}^{r} sum_{j=i}^{r}[(sum_{k=i}^{j} s_{k} imes 10^{j-k}) pmod P equiv 0] ]

    等价于

    [sum_{i=l}^{r} sum_{j=i}^{r} [10^{j} (sum_{k=i}^{j} s_{k} imes 10^{-k}) pmod P equiv 0] ]

    (P e 2 且 P e 5) 时,(p mid 10^j)
    所以原式等价于

    [sum_{i=l}^{r} sum_{j=i}^{r} [(sum_{k=i}^{j} s_{k} imes 10^{-k}) pmod P equiv 0] ]


    (a_k = s_k imes 10^{-k} pmod P)
    (sum_k = sum_{i=1}^{k} a_i pmod P)

    所以原式等价于

    [egin{split} & sum_{i=l}^{r} sum_{j=i}^{r} [(sum_{k=i}^{j} a_k) pmod P equiv 0] \ = &sum_{i=l}^{r} sum_{j=i}^{r} [(sum_j = sum_{i-1})] end{split} ]

    (sum) 离散化后转化为区间查询相等的数的个数
    莫队
    对于 (P = 2 或 P = 5) 的情况特判即可
    时间复杂度 (O(n^{1.5} + nlogn))

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 1e5 + 10;
    
    #define Rep(i, a, b) for(int i = a; i <= b; i ++)
    #define LL long long
    
    #define gc getchar()
    inline int read() {
    	int x = 0; char c = gc;
    	while(c < '0' || c > '9') c = gc;
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    	return x;
    }
    
    int P, n, m;
    char s[N];
    int pos[N], block;
    struct Node {
    	int l, r, id;
    	bool operator < (const Node a) const {
    		if(pos[this-> l] == pos[a.l]) return pos[this-> r] < pos[a.r];
    		return pos[this-> l] < pos[a.l];
    	}
    } Ask[N];
    
    LL S[N], A[N], Sum[N], Ten[N] = {0, 10};
    LL Copysum[N];
    LL Tong[N], Answer[N];
    
    LL Ksm(LL a, LL b) {
    	LL ret = 1;
    	while(b) {
    		if(b & 1) ret = ret * a % P;
    		a = a * a % P;
    		b >>= 1;
    	}
    	return ret;
    }
    
    LL Now_ans;
    
    inline void Cut(int x) {Tong[Sum[x]] --; Now_ans -= Tong[Sum[x]];}
    inline void Add(int x) {Now_ans += Tong[Sum[x]]; Tong[Sum[x]] ++;}
    
    void MoDui() {
    	int L = Ask[1].l, R = L - 1;
    	Rep(i, 1, m) {
    		int l = Ask[i].l - 1, r = Ask[i].r;
    		for(; L < l; L ++) Cut(L);
    		for(; R > r; R --) Cut(R);
    		for(; L > l; L --) Add(L - 1);
    		for(; R < r; R ++) Add(R + 1);
    		Answer[Ask[i].id] = Now_ans;
    	}
    }
    
    LL totsum[N], totcnt[N];
    
    void Special_Judge() {
    	Rep(i, 1, n) {
    		totcnt[i] = totcnt[i - 1] + ((s[i] - '0') % P == 0 ? 1 : 0);
    		totsum[i] = totsum[i - 1] + ((s[i] - '0') % P == 0 ? i : 0);
    	}
    	Rep(i, 1, m) {
    		int l =  Ask[i].l, r = Ask[i].r;
    		cout << totsum[r] - totsum[l - 1] - (l - 1) * (totcnt[r] - totcnt[l - 1]) << "
    ";
    	}
    }
    
    int main() {
    	P = read();
    	scanf("%s",s + 1);
    	n = strlen(s + 1);
    	m = read();
    	Rep(i, 1, m) Ask[i] = (Node) {read(), read(), i};
    	if(P == 2 || P == 5) {
    		Special_Judge(); return 0;
    	}
    	block = sqrt(n);
    	Rep(i, 1, n) pos[i] = (i - 1) / block + 1;
    	sort(Ask + 1, Ask + m + 1);
    	Rep(i, 1, n) S[i] = (s[i] - '0') % P;
    	Rep(i, 2, n) Ten[i] = (Ten[i - 1] * 10) % P;
    	Rep(i, 1, n) A[i] = S[i] * Ksm(Ten[i], P - 2) % P;
    	Rep(i, 1, n) Sum[i] = (Sum[i - 1] + A[i]) % P;
    	Rep(i, 1, n) Copysum[i] = Sum[i];
    	sort(Copysum + 1, Copysum + n + 1);
    	Rep(i, 1, n) Sum[i] = lower_bound(Copysum, Copysum + n + 1, Sum[i]) - Copysum;
    	MoDui();
    	Rep(i, 1, m) cout << Answer[i] << "
    ";
    	return 0;
    }
    
  • 相关阅读:
    java中的设计模式
    stack
    最大堆排序
    Starship Troopers
    Tick and Tick
    Last non-zero Digit in N!
    G
    C
    B
    A
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9719667.html
Copyright © 2020-2023  润新知