luogu P3245 [HNOI2016]大数 莫队

版权声明:_ https://blog.csdn.net/lunch__/article/details/84875340

题意

  • 给你一个由数字构成的字符串,每次询问一个区间内有多少个子区间满足子区间构成的数是 P P 的倍数。

这个题好像并没有那么裸,就有一个性质需要观察,当 P 2 P≠2 P 5 P≠5 的时候,令 f [ i ] f[i] 为以 i i 开始的后缀,那么只要 f [ l ] = = f [ r + 1 ] f[l]==f[r+1] ,区间 [ l , r ] [l,r] 构成的数是 P P 的倍数。令区间 [ l , r ] [l,r] 构成的数为 k k ,我们可以发现这样一个等式 f [ l ] = f [ r + 1 ] + 1 0 r l × k ( m o d   P ) f[l]=f[r+1]+10^{r-l}×k(mod \ P) ,当 1 0 r l   m o d   P 0 10^{r-l}\ mod\ P≠0 时,又因为 k = 0 k=0 ,所以 f [ l ] = f [ r + 1 ] f[l]=f[r+1] ,得出来这个之后就是一个莫队统计区间颜色个数的模板题了.

P = 2 P=2 P = 5 P=5 的情况计算比较容易,这里就不详细讲了

Codes

#include <bits/stdc++.h>

#define ll long long

using namespace std;

const int N = 1e5 + 10;

char S[N]; 

ll ans[N], c[N], res; 

int mod, q, n, size, cnt;
int be[N], f[N], pow10[N], tmp[N];

struct Que {
    int x, y, id; 
    bool operator < (const Que &T) const {
        if (be[x] == be[T.x]) return y < T.y;
        return be[x] < be[T.x];
    }
}Q[N];

void update(int x, int y) {
    res -= (c[x] - 1) * c[x] / 2;  
    c[x] += y; 
    res += (c[x] - 1) * c[x] / 2; 
}

int main() {
#ifdef ylsakioi
    freopen("2053.in", "r", stdin);
    freopen("2053.out", "w", stdout);
#endif

    scanf("%d%s%d", &mod, S + 1, &q);
    n = strlen(S + 1), size = sqrt(n);
    for (int i = 1; i <= q; ++ i) {
        scanf("%d%d", &Q[i].x, &Q[i].y), ++ Q[i].y;
        be[Q[i].x] = Q[i].x / size, Q[i].id = i;
    }
    sort(Q + 1, Q + q + 1); 

    if (mod == 2 || mod == 5) {
        for (int i = 1; i <= n; ++ i) {
            int flag = (S[i] ^ '0') % mod == 0;
            f[i] = f[i - 1] + i * flag;
            c[i] = c[i - 1] + flag; 
        }
        for (int i = 1; i <= q && (-- Q[i].y); ++ i) 
            ans[Q[i].id] = (f[Q[i].y] - f[Q[i].x - 1]) - (c[Q[i].y] - c[Q[i].x - 1]) * (Q[i].x - 1);
    }
    else {
        ll now = 1; tmp[cnt = 1] = 0;
        for (int i = n; i >= 1; -- i, (now *= 10) %= mod) 
            tmp[++ cnt] = f[i] = (now * (S[i] ^ '0') + f[i + 1]) % mod;
        sort(tmp + 1, tmp + cnt + 1); 
        cnt = unique(tmp + 1, tmp + cnt + 1) - tmp - 1;
        for (int i = 1; i <= n + 1; ++ i) 
            f[i] = lower_bound(tmp + 1, tmp + cnt + 1, f[i]) - tmp;
        int l = 1, r = 0; 
        for (int i = 1; i <= q; ++ i) {
            while (r < Q[i].y) update(f[++ r], 1);
            while (r > Q[i].y) update(f[r --], -1);
            while (l > Q[i].x) update(f[-- l], 1);
            while (l < Q[i].x) update(f[l ++], -1);
            ans[Q[i].id] = res; 
        }
    }

    for (int i = 1; i <= q; ++ i)
        printf("%lld\n", ans[i]);

    return 0;
}


猜你喜欢

转载自blog.csdn.net/lunch__/article/details/84875340