专栏首页数据结构与算法洛谷P3245 [HNOI2016]大数(莫队)

洛谷P3245 [HNOI2016]大数(莫队)

题意

题目链接

Sol

莫队板子题。。

维护出每个位置开始的字符串\(mod P\)的结果,记为\(S_i\)

两个位置\(l, r\)满足条件当且仅当\(S_l - S_r = 0\),也就是\(S_l = S_r\)

离散化之后直接上莫队就行了

对\(2, 5\)特判一下,因为2/5是10的因子,可能导致答案变大。直接维护\(0/5\)的出现次数就可以了

考场上一高兴写了三个Subtask。。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e6 + 10;
int mod;
template <typename A, typename B>
inline void mul2(A &x, B y) {
    x = 1ll * x * y % mod;
}
template <typename A, typename B>
inline int mul(A x, B y) {
    return 1ll * x * y % mod;
}
template <typename A, typename B>
inline int add(A x, B y) {
    return x + y >= mod ? x + y - mod : x + y;
}
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    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;
}
int N, Q, belong[MAXN], block, l, r;
LL now, ans[MAXN];
char s[MAXN];

namespace Sub3 {
int pro[MAXN], num, date[MAXN], cnt[MAXN];
void Des() {
    for (int i = 1; i <= N + 1; i++) date[++num] = pro[i];
    sort(date + 1, date + num + 1);
    num = unique(date + 1, date + num + 1) - date - 1;
    for (int i = 1; i <= N + 1; i++) pro[i] = lower_bound(date + 1, date + num + 1, pro[i]) - date;
}
struct Query {
    int l, r, id;
    bool operator<(const Query &rhs) const {
        return belong[l] == belong[rhs.l] ? r < rhs.r : belong[l] < belong[rhs.l];
    }
} q[MAXN];
void Add(int x) {
    now += cnt[x];
    cnt[x]++;
}
void Delet(int x) {
    cnt[x]--;
    now -= cnt[x];
}
void solve() {
    block = sqrt(N);
    for (int i = 1; i <= N; i++) belong[i] = (i - 1) / block + 1;
    for (int i = N, base = 1; i >= 1; i--, mul2(base, 10)) pro[i] = add(pro[i + 1], mul((s[i] - '0'), base));
    Des();
    Q = read();
    for (int i = 1; i <= Q; i++) q[i].l = read(), q[i].r = read() + 1, q[i].id = i;
    sort(q + 1, q + Q + 1);
    l = 1, r = 0;
    for (int i = 1; i <= Q; i++) {
        while (r < q[i].r) Add(pro[++r]);
        while (r > q[i].r) Delet(pro[r--]);
        while (l < q[i].l) Delet(pro[l++]);
        while (l > q[i].l) Add(pro[--l]);
        ans[q[i].id] = now;
    }
    for (int i = 1; i <= Q; i++) cout << ans[i] << '\n';
}
}  // namespace Sub3

namespace Sub1 {
int cnt[MAXN], a[MAXN];
struct Query {
    int l, r, id;
    bool operator<(const Query &rhs) const {
        return belong[l] == belong[rhs.l] ? r < rhs.r : belong[l] < belong[rhs.l];
    }
} q[MAXN];
void Add(int x, int opt) {
    if (opt) {
        if (x == 0)
            now += r - l + 1;
    } else {
        now += cnt[0];
    }
    cnt[x]++;
}
void Delet(int x, int opt) {
    cnt[x]--;
    if (opt) {
        if (x == 0)
            now -= r - l + 1;
    } else {
        now -= cnt[0];
    }
}
void solve() {
    block = sqrt(N);
    for (int i = 1; i <= N; i++) belong[i] = (i - 1) / block + 1, a[i] = (s[i] - '0') % 2;
    Q = read();
    for (int i = 1; i <= Q; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + Q + 1);
    l = 1, r = 0;
    for (int i = 1; i <= Q; i++) {
        while (r < q[i].r) Add(a[++r], 1);
        while (r > q[i].r) Delet(a[r--], 1);
        while (l < q[i].l) Delet(a[l++], 0);
        while (l > q[i].l) Add(a[--l], 0);
        ans[q[i].id] = now;
    }
    for (int i = 1; i <= Q; i++) cout << ans[i] << '\n';
}
}

namespace Sub2 {
int cnt[MAXN], a[MAXN], len[MAXN];
struct Query {
    int l, r, id;
    bool operator < (const Query &rhs) const {
        return belong[l] == belong[rhs.l] ? r < rhs.r : belong[l] < belong[rhs.l];
    }
}q[MAXN];
void Add(int x, int opt, int pos) {
    cnt[x]++;
    if(opt) {
        if(x == 0 || x == 5) now += r - l + 1;
    } else {
        now += cnt[0] + cnt[5];
    }
    
}
void Delet(int x, int opt, int pos) {
    if(opt) {
        if(x == 0 || x == 5) now -= r - l + 1;
    } else {
        now -= cnt[0] + cnt[5];
    }
    cnt[x]--;
}
void solve() { 
    block = sqrt(N);
    for(int i = 1; i <= N; i++) belong[i] = (i - 1) / block + 1, a[i] = s[i] - '0';
    Q = read();
    for(int i = 1; i <= Q; i++) q[i].l = read(), q[i].r = read(), q[i].id = i;
    sort(q + 1, q + Q + 1);
    l = 1, r = 0;
    for(int i = 1; i <= Q; i++) {   
        while(l > q[i].l) 
            --l, Add(a[l], 0, l);
        while(r > q[i].r) 
            Delet(a[r], 1, r), r--;
        while(l < q[i].l) 
            Delet(a[l], 0, l), l++;
        while(r < q[i].r) 
            ++r, Add(a[r], 1, r);
        ans[q[i].id] = now;
    }
    for(int i = 1; i <= Q; i++) cout << ans[i] << '\n';
}

}

int main() {
    mod = read();
    scanf("%s", s + 1);
    N = strlen(s + 1);
    if (mod == 2)
        Sub1::solve();
    else if (mod == 5)
        Sub2::solve();
    else
        Sub3::solve();
    return 0;
}
/*
11
1211
1
1 4
*/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)

    考虑K比较小的情况,可以直接暴力建SAM, 枚举w的子串算出现次数。询问用个 的vector记录一下每次在vector里二分就好。

    attack
  • BZOJ2535: [Noi2010]Plane 航空管制2(拓扑排序 贪心)

    首先不难想到拓扑排序,但是直接对原图按\(k\)从小到大拓扑排序是错的。因为当前的\(k\)大并不意味着后面的点\(k\)也大

    attack
  • BZOJ4010: [HNOI2015]菜肴制作(拓扑排序 贪心)

    attack
  • BZOJ4010: [HNOI2015]菜肴制作(拓扑排序 贪心)

    attack
  • 作业比赛编号 : 100000575 - 《算法笔记》3.1小节——入门模拟->简单模拟

    网址:http://codeup.cn/contest.php?cid=100000575

    种花家的奋斗兔
  • 2189 数字三角形W

    2189 数字三角形W 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题目描述 Description 数字三角...

    attack
  • BZOJ2535: [Noi2010]Plane 航空管制2(拓扑排序 贪心)

    首先不难想到拓扑排序,但是直接对原图按\(k\)从小到大拓扑排序是错的。因为当前的\(k\)大并不意味着后面的点\(k\)也大

    attack
  • 洛谷P4723 【模板】线性递推(多项式取模 线性代数)

    attack
  • loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)

    考虑K比较小的情况,可以直接暴力建SAM, 枚举w的子串算出现次数。询问用个 的vector记录一下每次在vector里二分就好。

    attack
  • agc007B - Construct Sequences(构造)

    attack

扫码关注云+社区

领取腾讯云代金券