1150 字
6 分钟
[NOI2017] 蚯蚓排队
2017-08-09

题目描述 蚯蚓幼儿园有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); } } }
[NOI2017] 蚯蚓排队
https://www.nekomio.com/posts/82/
作者
NekoMio
发布于
2017-08-09
许可协议
CC BY-NC-SA 4.0