Description
给出
n
n
个字符,初始每个字符单独成字符串。支持次操作,每次为一下三种之一:
1
1
j
j
:将以结尾的串和以
j
j
开头的串连到一起。
i
i
:将所在串从
i
i
位置和下一个位置之间断开。
3
3
k
k
:对于字符串每个长度为
k
k
的子串,统计它在这个字符组成所有字符串中出现的次数,求所有统计结果的乘积模
998244353
998244353
的结果。
n≤2e5
n
≤
2
e
5
m≤3e5
m
≤
3
e
5
Σ|s|<1e7
Σ
|
s
|
<
1
e
7
k≤50
k
≤
50
2
2
操作次数小于
Solution
(●´∀`)♪我miao掉了好开心啊,我原来这么厉害啊哈哈哈哈哈
蛤蛤蛤开始码码码码码码码码码码码码码码码码码码码码码码码码
(っ °Д °;)っ啊啊啊为毛球不对啊啊啊啊啊啊啊啊啊啊啊啊啊啊
(っ °Д °;)っ啊啊啊大样例WAWAWAWAWAWAWAWAWAWAWAWAWA
(/゚Д゚)/ 为毛球换个模数错的地方就不一样了啊,只好承认自己菜去抄题解
(/゚Д゚)/ 你什么东西啊,先自然溢然后哈希表,只好%%%%%%%%%
事实证明没有卡自然溢,大家以后可以放心使用。。
我开始用了几个
1e6
1
e
6
级别的模数,直接开
M∗P
M
∗
P
的数组记
cnt
c
n
t
,都死的很惨。。。
那么白菜
miaowey
m
i
a
o
w
e
y
又涨了姿势,用自然溢套哈希表!
(对了让我们背好长者的生日吧这是个质数蛤蛤蛤
19260817
19260817
)
Source
//2018-4-24
//miaowey
//Read()
#include <bits/stdc++.h>
using namespace std;
#define ULL unsigned long long
#define For(i, a, b) for(int i = (a); i <= (int)(b); ++i)
#define M (50 + 2)
#define N (200000 + 2)
char chr;
inline void Read(int &x){
chr = getchar();
while(chr < '0' || chr > '9') chr = getchar();
x = 0;
while(chr >= '0' && chr <= '9'){
x = (x << 1) + (x << 3) + (chr ^ '0');
chr = getchar();
}
}
const ULL A = 7;
const int P = 19260817, RP = 998244353;
struct node{
int pre, nxt, len; ULL num[M];
}h[N];
namespace HashTable{
int hn, head[P], to[10000005], nxt[10000005], tot[10000005];
ULL val[10000005];
void Insert(int id, ULL nv, int ad){
int o = nv % P;
for(int i = head[o]; i; i = nxt[i]) if(to[i] == id && val[i] == nv){
tot[i] += ad; return;
}
to[++hn] = id; nxt[hn] = head[o]; head[o] = hn;
tot[hn] += ad; val[hn] = nv;
}
int Query(int id, ULL nv){
int o = nv % P;
for(int i = head[o]; i; i = nxt[i]) if(to[i] == id && val[i] == nv) return tot[i];
return 0;
}
};
int n, m, s[N];
ULL powa[M];
char rs[10000005];
void Unit(int u, int v){
h[v].pre = u; h[u].nxt = v;
int T = 50, cnt = 0, len = h[v].len;
ULL add[M];
For(i, 0, len) add[i] = h[v].num[i];
while(T --){
For(i, 1, len) add[i] = add[i] + powa[i + cnt] * s[u];
++cnt;
if(len + cnt > 50) --len;
For(i, cnt + 1, cnt + len){
h[u].num[i] = add[i - cnt], ++h[u].len;
HashTable::Insert(i, h[u].num[i], 1);
}
if(!(u = h[u].pre) || !len) break;
}
}
void Cut(int u){
int v = h[u].nxt;
h[u].nxt = h[v].pre = 0;
int T = 50, len = 0;
while(T --){
int flen = h[u].len;
h[u].len = ++len;
For(i, len + 1, flen) HashTable::Insert(i, h[u].num[i], -1);
if(!(u = h[u].pre)) break;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("queue5.in", "r", stdin);
freopen("queue.out", "w", stdout);
#endif
powa[0] = 1;
For(i, 1, 50) powa[i] = powa[i - 1] * A;
Read(n), Read(m);
For(i, 1, n){
Read(s[i]); h[i].num[1] = s[i];
h[i].len = 1; HashTable::Insert(1, s[i], 1);
}
int op, u, v, k, rlen;
while(m --){
Read(op);
if(op == 1){
Read(u), Read(v); Unit(u, v);
}else if(op == 2){
Read(u); Cut(u);
}else{
scanf("%s", rs + 1); Read(k);
rlen = strlen(rs + 1);
ULL now = 0; int ans = 1;
For(i, 1, k - 1) now = now * A + (rs[i] - '0');
For(i, k, rlen){
now = now * A + (rs[i] - '0');
ans = (long long)ans * (HashTable::Query(k, now)) % RP;
now -= powa[k - 1] * (rs[i - k + 1] - '0');
}
printf("%d\n", ans);
}
}
return 0;
}