[NOI2017] 蚯蚓排队

题目描述
蚯蚓幼儿园有nnn只蚯蚓。幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演。

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

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

给出 i 和 j ,令 i 号蚯蚓与 j 号蚯蚓所在的两个队伍合并为一个队伍,具体来说,令 j 号蚯蚓紧挨在 i 号蚯蚓之后,其余蚯蚓保持队伍的前后关系不变。
给出 i ,令 i 号蚯蚓与紧挨其后的一只蚯蚓分离为两个队伍,具体来说,在分离之后, i 号蚯蚓在其中一个队伍的队尾,原本紧挨其后的那一只蚯蚓在另一个队伍的队首,其余蚯蚓保持队伍的前后关系不变。
给出一个正整数 k 和一个长度至少为 k 的数字串 s ,对于 s 的每个长度为 k 的连续子串 t (这样的子串共有 ∣s∣−k+1 个,其中 ∣s∣|s|∣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,m ,分别表示蚯蚓的只数与操作次数。

第二行包含 n 个不超过 6 的正整数,依次表示编号为
1,2,…,n的蚯蚓的长度。

!!!

不想粘题了

好气

链接LOJ

题解

哈希能过
但要注意一下

每合并一次就相当于增加了50^2种情况
合并和拆分是一样的
然后查询的时候硬跑就可以了

#include <cstdio>
#include <cstring>
using namespace std;
#define LL unsigned long long
const int N = 300010, M = 15000010, L = 20000010;
const LL P = 23333333, p = 1000007, mod = 998244353;
int head[P], next[L], cnt[L], E, Next[N], Pre[N], a[N];
LL w[L], Pow[60];
int n, m;
char str[L];
void Insert(LL x, int y)
{
    LL now = x % P;
    bool flag = 0;
    for (int i = head[now]; i; i = next[i])
        if (w[i] == x)
        {
            cnt[i] += y;
            flag = 1;
            break;
        }
    if (!flag)
    {
        next[++E] = head[now];
        head[now] = E;
        cnt[E] = 1;
        w[E] = x;
    }
}
int Query(LL x)
{
    LL now = x % P;
    for (int i = head[now]; i; i = next[i])
        if (w[i] == x)
            return cnt[i];
    return 0;
}
void Change(int x, int y)
{
    int now = x;
    for (int k = 1; k <= 50; k++)
    {
        int ret = now;
        LL Hash = a[now];
        for (int j = 1; j <= k; j++)
        {
            ret = Next[ret];
            Hash = Hash * p + a[ret];
        }
        for (int l = k + 1; l <= 50; l++)
        {
            Insert(Hash, y);
            ret = Next[ret];
            if (!ret)
                break;
            Hash = Hash * p + a[ret];
        }
        now = Pre[now];
        if (!now)
            break;
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        Insert(a[i], 1);
    }
    Pow[0] = 1;
    for (int i = 1; i <= 50; i++)
    {
        Pow[i] = Pow[i - 1] * p;
    }
    int op;
    int x, y;
    for (int i = 1; i <= m; i++)
    {
        scanf("%d", &op);
        if (op == 1)
        {
            scanf("%d%d", &x, &y);
            Next[x] = y;
            Pre[y] = x;
            Change(x, 1);
        }
        else if (op == 2)
        {
            scanf("%d", &x);
            Change(x, -1);
            Pre[Next[x]] = 0, Next[x] = 0;
        }
        else
        {
            scanf("%s", str + 1);
            scanf("%d", &x);
            LL ret = 0;
            for (int i = 1; i <= x; i++)
                ret = ret * p + str[i] - '0';
            LL ans = Query(ret);
            LL len = strlen(str + 1);
            for (int i = x + 1; i <= len; i++)
            {
                ret = ret - (str[i - x] - '0') * Pow[x - 1];
                ret = ret * p + (str[i] - '0');
                ans = ans * Query(ret) % mod;
            }
            printf("%lld\n", ans);
        }
    }
}
本文作者 : NekoMio
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本文链接 : https://www.nekomio.com/2017/08/09/82/
上一篇
下一篇