• [NOI 2017]蚯蚓排队


    Description

    题库链接

    蚯蚓幼儿园有 (n) 只蚯蚓。幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演。

    所有蚯蚓用从 (1)(n) 的连续正整数编号。每只蚯蚓的长度可以用一个正整数表示,根据入园要求,所有蚯蚓的长度都不超过 (6) 。神刀手希望这些蚯蚓排成若干个队伍,初始时,每只蚯蚓各自排成一个仅有一只蚯蚓的队伍,该蚯蚓既在队首,也在队尾。

    神刀手将会依次进行 (m) 次操作,每个操作都是以下三种操作中的一种:

    1.给出 (i)(j) ,令 (i) 号蚯蚓与 (j) 号蚯蚓所在的两个队伍合并为一个队伍,具体来说,令 (j) 号蚯蚓紧挨在 (i) 号蚯蚓之后,其余蚯蚓保持队伍的前后关系不变。
    2.给出 (i) ,令 (i) 号蚯蚓与紧挨其后的一只蚯蚓分离为两个队伍,具体来说,在分离之后, (i) 号蚯蚓在其中一个队伍的队尾,原本紧挨其后的那一只蚯蚓在另一个队伍的队首,其余蚯蚓保持队伍的前后关系不变。
    3.给出一个正整数 (k) 和一个长度至少为 (k) 的数字串 (s) ,对于 (s) 的每个长度为 (k) 的连续子串 (t) (这样的子串共有 (|s| - k + 1) 个,其中 (|s|)(s) 的长度),定义函数 (f(t)) ,询问所有这些 (f(t)) 的乘积对 (998244353) 取模后的结果。其中 (f(t)) 的定义如下: 对于当前的蚯蚓队伍,定义某个蚯蚓的向后 (k) 数字串为:从该蚯蚓出发,沿队伍的向后方向,寻找最近的 (k) 只蚯蚓(包括其自身),将这些蚯蚓的长度视作字符连接而成的数字串;如果这样找到的蚯蚓不足 (k) 只,则其没有向后 (k) 数字串。例如蚯蚓的队伍为 (10) 号蚯蚓在队首,其后是 (22) 号蚯蚓,其后是 (3) 号蚯蚓(为队尾),这些蚯蚓的长度分别为 (4)(5)(6) ,则 (10) 号蚯蚓的向后 (3) 数字串 为456, (22) 号蚯蚓没有向后 (3) 数字串,但其向后 (2) 数字串为56,其向后 (1) 数字串为5。

    (f(t)) 表示所有蚯蚓中,向后 (k) 数字串恰好为 (t) 的蚯蚓只数。

    保证 (n leqslant 2 imes 10^5, m leqslant 5 imes 10^5, k leqslant 50) 。设 (sum |S|) 为某个输入文件中所有询问的 s 的长度总和,则 (sum |S| leqslant 10^7) 。 设 (c) 为某个输入文件中形如 2 i 的操作的次数,则 (c leqslant 10^3)

    Solution

    由于 (k) 比较小,直接 (hash) 就行了。复杂度是正确的,因为整个字符串需被 (hash) 的子串是 (O(nk)) 的。由于 (cleq 10^3) ,所以修改的字符串复杂度是 (O(ck^2)) 的。

    总复杂度是 (Oleft(nk+ck^2+sum|S| ight))

    Code

    #include <bits/stdc++.h>
    #define ull unsigned long long
    using namespace std;
    const int N = 2e5+5, LEN = 1e7+5, yzh = 998244353, p = 12456791, base = 31;
    void gi(int &x) {
        char ch = getchar(); x = 0;
        for (; ch < '0' || ch > '9'; ch = getchar());
        for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x<<1)+(x<<3)+ch-48;
    }
    
    char ch[LEN];
    int n, m, l[N], lst[N], nxt[N], opt, x, y, k;
    ull bin[N], tmp;
    struct hash_table {
        int cnt[p]; ull ky[p];
        void insert(ull x, int val) {
            int loc = x%p;
            while (true) {
                if (ky[loc] == 0 || ky[loc] == x) {cnt[loc] += val, ky[loc] = x; break; }
                ++loc; if (loc == p) loc = 0;
            }
        }
        int count(ull x) {
            int loc = x%p;
            while (true) {
                if (ky[loc] == 0 || ky[loc] == x) return cnt[loc];
                ++loc; if (loc == p) loc = 0;
            }
        }
    }mp;
    
    void merge() {
        int t = 48, loc = x;
        while (t-- && lst[loc]) loc = lst[loc];
        lst[y] = x, nxt[x] = y;
        for (; lst[loc] != x; loc = nxt[loc]) {
            bool flag = 0; t = loc; tmp = 0;
            for (int j = 1; j <= 50 && t; j++, t = nxt[t]) {
                tmp = tmp*base+l[t];
                if (flag) mp.insert(tmp, 1);
                if (t == x) flag = 1;
            }
        }
    }
    void split() {
        int t = 48, loc = x; y = nxt[x];
        while (t-- && lst[loc]) loc = lst[loc];
        for (; lst[loc] != x; loc = nxt[loc]) {
            bool flag = 0; t = loc; tmp = 0;
            for (int j = 1; j <= 50 && t; j++, t = nxt[t]) {
                tmp = tmp*base+l[t];
                if (flag) mp.insert(tmp, -1);
                if (t == x) flag = 1;
            }
        }
        lst[y] = nxt[x] = 0;
    }
    int query() {
        int n = strlen(ch+1), ans = 1; tmp = 0;
        for (int i = 1; i <= n; i++) {
            tmp = tmp*base+ch[i]-48;
            if (i > k) tmp -= 1ll*(ch[i-k]-48)*bin[k];
            if (i >= k) ans = 1ll*ans*mp.count(tmp)%yzh;
        }
        return ans;
    }
    void work() {
        gi(n), gi(m); bin[0] = 1;
        for (int i = 1; i <= n; i++) gi(l[i]), mp.insert(l[i], 1);
        for (int i = 1; i <= 50; i++) bin[i] = bin[i-1]*base;
        while (m--) {
            gi(opt);
            if (opt == 1) gi(x), gi(y), merge();
            else if (opt == 2) gi(x), split();
            else scanf("%s", ch+1), gi(k), printf("%d
    ", query());
        }
    }
    int main() {
        freopen("queue.in", "r", stdin);
        freopen("queue.out", "w", stdout);
        work(); return 0;
    }
  • 相关阅读:
    EclipseTool_v1.0.4(eclipse整合开发工具)
    51单片机堆栈深入剖析
    3.进程
    解决卡巴斯基安装失败的一个方法.
    9.串口操作之API篇 ReadFile WriteFile CloseHandle 及总结
    2.内核对象之<创建和关闭内核对象,跨进程共享>
    1.内核对象之<什么是内核对象,使用计数及安全性>
    TeeChart使用小技巧之 点击Series显示名称
    TeeChart使用小技巧之 曲线分页显示,轴分别显示日期
    8.串口操作之API篇 PurgeComm ClearCommError
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9286094.html
Copyright © 2020-2023  润新知