[BZOJ4542]大数

来源:互联网 发布:网络投影仪怎么用 编辑:程序博客网 时间:2024/06/05 06:53

题目链接:BZOJ4542

题目大意
给出一个数字串,问某个子串有多少个子串可以被P整除。N1e5

分析
1. 又是一道长得就非常莫队的题,思考怎么转移。
2. 当P2P5时。设suf[i]为从i开始的后缀modP的值,如果有suf[i]=suf[j]ij,那么子串num[l..j1]modP=0
3. 证明:设num[i..j1]=Anum[j..n]=B,则有A×10lenthB+BBmodP,又10lenthBmodP0,所以AmodP=0
4. 那么询问就变成了:问区间[l..r+1]内有多少对相等的suf,经典的莫队题目。
5. 当P=2P=5时,可以直接由子串的最后一位判断。

上代码

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int SQR = 320;const int N = 1e5 + 10;int n, m, mod;char ss[N];inline int read() {    char ch;    int ans = 0, neg = 1;    while (ch = getchar(), ch < '0' || ch > '9')        if (ch == '-') neg = -1;    while (ch >= '0' && ch <= '9')        ans = ans * 10 + ch - '0', ch = getchar();    return ans * neg;}struct nodeQry {    int l, r, bl, id, ans;    nodeQry() {}    nodeQry(int a, int b) : l(a), r(b) { bl = l / SQR; }    inline void input(int a) {        l = read(), r = read() + 1, bl = l / SQR, id = a;    }    inline bool operator < (const nodeQry &a) const {        return (bl != a.bl ? (bl < a.bl) : (r < a.r));    }} qry[N];struct nodeAns {    int id; LL ans;    nodeAns() {}    nodeAns(int a, LL b) : id(a), ans(b) {}    inline bool operator < (const nodeAns &a) const {        return id < a.id;    }} ans[N];namespace ans1 {    int pT[N], val[N];    struct node {        int id, val;        inline bool operator < (const node &a) const {            return val < a.val;        }    } map[N];    void init() {        pT[0] = 1;        for (int i = 1; i <= n; i++)            pT[i] = (LL)pT[i - 1] * 10 % mod;        for (int i = n; i >= 1; i--) {            val[i] = ((LL)(ss[i] - '0') * pT[n - i] + val[i + 1]) % mod;            map[i].id = i, map[i].val = val[i];        } sort(map + 1, map + n + 1);        int cnt = 0;        for (int i = 1; i <= n; i++)            if (map[i].val != map[i - 1].val)                val[map[i].id] = ++cnt;            else val[map[i].id] = cnt;    }    LL tot;    int cnt[N];    void figure() {        nodeQry tmp = nodeQry(qry[1].l, qry[1].l);        cnt[val[tmp.l]]++;        for (int i = 1; i <= m; i++) {            while (tmp.r < qry[i].r) tot += (LL)cnt[val[++tmp.r]]++;            while (tmp.l > qry[i].l) tot += (LL)cnt[val[--tmp.l]]++;            while (tmp.r > qry[i].r) tot -= (LL)--cnt[val[tmp.r--]];            while (tmp.l < qry[i].l) tot -= (LL)--cnt[val[tmp.l++]];            ans[i] = nodeAns(qry[i].id, tot);        } sort(ans + 1, ans + m + 1);        for (int i = 1; i <= m; i++) printf("%lld\n", ans[i].ans);    }    void main() {        init();        figure();    }}namespace ans2 {    int val[N];    void init() {        for (int i = 1; i <= n; i++) val[i] = ss[i] - '0';    }    LL tot;    int cnt;    void figure() {        nodeQry tmp = nodeQry(qry[1].l, qry[1].l);        tot = cnt = val[tmp.l] % mod ? 0 : 1;        for (int i = 1; i <= m; i++) {            qry[i].r--;            while (tmp.r < qry[i].r)                if (!(val[++tmp.r] % mod))                    cnt++, tot += (LL)(tmp.r - tmp.l + 1);            while (tmp.l > qry[i].l) {                if (!(val[--tmp.l] % mod)) cnt++;                tot += (LL)cnt;            }            while (tmp.r > qry[i].r)                if (!(val[tmp.r--] % mod))                    cnt--, tot -= (LL)(tmp.r - tmp.l + 2);            while (tmp.l < qry[i].l) {                tot -= (LL)cnt;                if (!(val[tmp.l++] % mod)) cnt--;            }            ans[i] = nodeAns(qry[i].id, tot);        } sort(ans + 1, ans + m + 1);        for (int i = 1; i <= m; i++)            printf("%lld\n", ans[i].ans);    }    void main() {        init();        figure();    }}int main() {    scanf("%d %s", &mod, ss + 1);    n = strlen(ss + 1), scanf("%d", &m);    for (int i = 1; i <= m; i++)        qry[i].input(i);    sort(qry + 1, qry + m + 1);    if (mod != 2 && mod != 5)        ans1::main();    else ans2::main(); // 哇,感觉我的ans2写得比ans1丑多了    return 0;}

以上

0 0
原创粉丝点击