[硫化铂]T3
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[硫化铂]T3相关的知识,希望对你有一定的参考价值。
T3
题目概述
题解
这名字也太草了。
首先,字符串同构的定义是,二者是循环同构的。
我们先考虑对于一个不是很长的给定串
T
T
T,我们查询它里面与
S
S
S循环同构的子串有多少。
既然是循环同构,那么我们显然可以去考虑将所有循环同构的部分都放过去查一查。
但如果所有循环串去查的话那不就达到
M
2
M^2
M2了吗,没事,我们可以的循环同构一定可以被看成
一
段
前
缀
+
一
段
后
缀
一段前缀+一段后缀
一段前缀+一段后缀的形式,我们可以考虑对于前后缀各做一个KMP,然后拼起来看每个位置能否填满。
但事实上这样是不可能过的,毕竟每次询问都会达到
O
(
∣
S
∣
+
∣
T
∣
)
O\\left(|S|+|T|\\right)
O(∣S∣+∣T∣),显然不可能过。
但我们完全可以优化这个复杂度嘛。
我们发现前后缀做
K
M
P
KMP
KMP也太麻烦了,我们可以转化一下,将两个
S
S
S串拼在一起,那么里面的任意一个长度为
∣
S
∣
|S|
∣S∣的子串,都可以表示原
S
S
S串的一个循环同构。
于是,我们查询的就成了我们
S
S
SS
SS串中哪些位置对应的前缀的长度至少为
∣
S
∣
|S|
∣S∣的后缀在
∣
T
∣
|T|
∣T∣中出现。
我们不妨将我们的
T
T
T串建一个后缀自动机,查询串的时候就直接在串上用双指针跑,走
c
h
i
l
d
r
e
n
children
children的边就相当于让我们的
r
+
+
r++
r++,而跳父亲边回退也就是让我们的
l
+
+
l++
l++。
由于我们的父亲位置的
l
e
n
len
len记录的是该位置的最长公共串长度,而有可能我们的
r
−
l
+
1
r-l+1
r−l+1完全小于该节点上的
l
e
n
len
len,也就是说我们匹配的不是该节点的最长串,只是一个前缀的子串。但没关系,我们向父亲跳不过是让我们的
l
,
r
l,r
l,r间的距离不超过
l
e
n
len
len,让
l
=
max
(
l
,
r
−
l
e
n
+
1
)
l=\\max(l,r-len+1)
l=max(l,r−len+1)。
我们就找到能使得
l
,
r
l,r
l,r不小于
∣
S
∣
|S|
∣S∣的最高的点,如果有的话,我们就能够知道这种循环同构在
T
T
T上有多少一样的子串了。
当然,我们的两个
S
S
S拼在一起不一定组成的每个长为
∣
S
∣
|S|
∣S∣的子串都是不同的。这个只需要我们预先用
K
M
P
KMP
KMP处理一下,如果某个点的
f
a
i
l
fail
fail不小于
∣
S
∣
|S|
∣S∣,就不算它的贡献就行了。
这样预处理每个后缀自动机,我们的查询就是
O
(
∣
S
∣
)
O\\left(|S|\\right)
O(∣S∣)的了。
但是我们的
i
d
⩽
1
0
18
id\\leqslant 10^18
id⩽1018,不说要处理极多的后缀自动机,每个串还是极长的,显然不大现实。
可我们发现,我们实际上只需要找到它们最小的
i
i
i使得
∣
S
i
∣
⩾
∣
S
∣
|S_i|\\geqslant |S|
∣Si∣⩾∣S∣,那样的话,我们匹配的位置要么被
S
i
S_i
Si或者
S
i
+
1
S_i+1
Si+1完全包含,要么就是在它们之间。
也就是说,我们的
S
i
d
S_id
Sid肯定是由许多个
S
i
S_i
Si和
S
i
+
1
S_i+1
Si+1拼接而成,我们只需要算一下
S
i
,
S
i
+
1
S_i,S_i+1
Si,Si+1内部,
S
i
S
i
+
1
,
S
i
+
1
S
i
+
1
,
S
i
+
1
S
i
S_iS_i+1,S_i+1S_i+1,S_i+1S_i
SiSi+1,Si+1Si+1,Si+1Si拼接处的贡献就行。
然后之后就只用用矩阵算出这
5
5
5种贡献每个的系数,加起来就可以了。
由于我们的
∣
S
i
∣
|S_i|
∣Si∣的增大是斐波拉契形式,也就是指数级的,也就是说,我们的后缀自动机只会有
log
∣
S
i
∣
\\log |S_i|
log∣Si∣个,每个都建出来算算就行。
由于我们的
∣
M
∣
|M|
∣M∣达到了
1
0
6
10^6
106级别,空间可能有点大,建议离线下来,建一个算一个。
记矩阵长度为 d d d,时间复杂度 O ( n + M + q d 3 log i d ) O\\left(n+M+qd^3\\log id\\right) O(n+M+qd3logid)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define MAXM 8000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int mod=1e5+7;
const int inv2=499122177;
const int inv3=332748118;
const double jzm=0.999;
const int zero=2000;
const int n1=100;
const int lim=100000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-8;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
void print(_T x)if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');
LL gcd(LL a,LL b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
char str[MAXN];bool vis[26];LL id[MAXN];
int s[2][MAXM],st[MAXN],ed[MAXN],dp[MAXN][5],ip[MAXN];
int len[2],idx,f[55],q,totf,sta[MAXM],stak;
vector<int>vec[55];
struct matrix
int c[15][15];matrix()
void clear()for(int以上是关于[硫化铂]T3的主要内容,如果未能解决你的问题,请参考以下文章