[硫化铂]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 rl+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,rlen+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 id1018,不说要处理极多的后缀自动机,每个串还是极长的,显然不大现实。
可我们发现,我们实际上只需要找到它们最小的 i i i使得 ∣ S i ∣ ⩾ ∣ S ∣ |S_i|\\geqslant |S| SiS,那样的话,我们匹配的位置要么被 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| logSi个,每个都建出来算算就行。
由于我们的 ∣ 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的主要内容,如果未能解决你的问题,请参考以下文章

[硫化铂]启程的日子

[硫化铂]签到题

[硫化铂]题目名称

[硫化铂]舰队游戏

[硫化铂]守序划分问题

[硫化铂]传染