洛谷 P7879 -「SWTR-07」How to AK NOI?(后缀自动机+线段树维护矩乘)
orz 一发出题人(话说我 AC 这道题的时候,出题人好像就坐在我的右侧呢/cy/cy)
考虑一个很 naive 的 DP,\(dp_i\) 表示 \([l,i]\) 之间的字符串是否可以被识别,转移就枚举上一段的终止为止,然后 SAM/哈希判断子串是否在 \(s\) 中出现过。
注意到一个事实:所有长度 \(>2k\) 的字符串都可以由长度 \(\ge k\) 的字符串拼成,也就是说只有长度在 \([k,2k]\) 的字符串是有用的,故每次转移只用枚举 \(k+1\) 个转移点。注意到 \(k\) 的数据范围很小,因此我们可以考虑矩阵优化转移,即对于大小分别为 \(n\times m\) 和 \(m\times k\) 的矩阵 \(A,B\),定义其乘积 \(C\) 满足 \(C_{i,j}=\text{or}_{t=1}^mA_{i,t}\land B_{t,j}\),那么
dp_{i}&dp_{i-1}&\cdots&dp_{i-2k+1}
\end{bmatrix}
=
\begin{bmatrix}
dp_{i-1}&dp_{i-2}&\cdots&dp_{i-2k}
\end{bmatrix}
\times
\begin{bmatrix}
g_1&1&0&0&\cdots&0\\
g_2&0&1&0&\cdots&0\\
g_3&0&0&1&\cdots&0\\
\vdots&\vdots&\vdots&\vdots&\ddots&\vdots\\
g_{2k-1}&0&0&0&\cdots&1\\
g_{2k}&0&0&0&\cdots&0
\end{bmatrix}
\]
其中 \(g_j\) 表示 \([i-j+1,i]\) 是否为 \(s\) 的子串。
显然每次修改一个区间最多改变 \(r-l+1+2k\) 个位置的转移矩阵,因此我们有一个很自然的想法:线段树维护矩阵乘积,每次暴力修改线段树对应的位置的值,求一个位置的转移矩阵可用 SAM。查询就求一遍区间矩阵乘积,这样复杂度大概是 \((L+qk)·k^3\log n+qk^3\log n\),显然无法通过,不过这里矩阵每个元素都是 0/1,因此可以用位运算加速实现 \(k^2\) 矩阵乘法,这样复杂度可达到 \((L+qk)·k^2\log n+qk^2\log n\),还是无法通过。再观察到每次修改是一段区间,因此考虑对这一段区间上的叶子节点到根节点路径的并上的节点,重新计算它们转移矩阵的乘积,这样假设待重构的区间长度为 \(len\),每次重构需要进行矩阵乘法的次数大概是 \(\sum\limits_{n}\lfloor\dfrac{len}{n}\rfloor=\mathcal O(len)\) 级别的,这样加号前面的 \(\log n\) 可以省去,复杂度就达到了 \((L+qk)·k^2+qk^2\log n\),可以通过。
const int MAXN=3e6;
const int MAXM=3e5;
const int MAXP=6e6;
const int MAXK=16;
int n,m,k,qu;char s[MAXN+5],t[MAXM+5];
int ch[MAXP+5][9],len[MAXP+5],lnk[MAXP+5],cur=1,ncnt=1;
void extend(char c){
int id=c-'a',nw=++ncnt,p=cur;
len[nw]=len[cur]+1;cur=nw;
while(p&&!ch[p][id]) ch[p][id]=nw,p=lnk[p];
if(!p) return lnk[nw]=1,void();
int q=ch[p][id];
if(len[q]==len[p]+1) return lnk[nw]=q,void();
int cl=++ncnt;len[cl]=len[p]+1;
lnk[cl]=lnk[q];lnk[q]=lnk[nw]=cl;
for(int i=0;i<9;i++) ch[cl][i]=ch[q][i];
while(p&&ch[p][id]==q) ch[p][id]=cl,p=lnk[p];
}
struct mat{
int a[MAXK+2];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat res;
for(int i=0;i<k*2;i++) for(int j=0;j<k*2;j++)
if(a[i]>>j&1) res.a[i]|=rhs.a[j];
return res;
}
void print(){
for(int i=0;i<k+k;i++) for(int j=0;j<k+k;j++)
printf("%d%c",a[i]>>j&1,"\0\n"[j==k+k-1]);
}
};
int lf[MAXM+5],used[MAXM*4+5];
mat calc(int l){
mat ret;
for(int i=0;i+1<k+k;i++) ret.a[i]|=1<<i+1;
int curp=1;
for(int i=1;i<=min(l,k+k);i++){
if(!ch[curp][t[l-i+1]-'a']) break;
curp=ch[curp][t[l-i+1]-'a'];
if(i>=k) ret.a[i-1]|=1;
}
// printf("calc %d\n",l);
// ret.print();
return ret;
}
namespace segtree{
struct node{int l,r;mat v;} s[MAXM*4+5];
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;
if(l==r){s[k].v=calc(l),lf[l]=k;return;}
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
s[k].v=s[k<<1].v*s[k<<1|1].v;
}
void rebuild(int k){
if(!used[k]) return;used[k]=0;
if(s[k].l==s[k].r) return;
rebuild(k<<1);rebuild(k<<1|1);
s[k].v=s[k<<1].v*s[k<<1|1].v;
}
mat query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].v;
int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return query(k<<1,l,mid)*query(k<<1|1,mid+1,r);
}
}
void rebuild(int l,int r){
static char buf[MAXM+5];scanf("%s",buf+1);
for(int i=l;i<=r;i++) t[i]=buf[i-l+1];
for(int i=l;i<=min(r+k+k,m);i++){
for(int j=lf[i];j;j>>=1) used[j]=1;
segtree::s[lf[i]].v=calc(i);
} segtree::rebuild(1);
}
int main(){
// freopen("passage.in","r",stdin);
// freopen("passage.out","w",stdout);
scanf("%*d%s%s%d%d",s+1,t+1,&k,&qu);
n=strlen(s+1);m=strlen(t+1);
for(int i=n;i;i--) extend(s[i]);
segtree::build(1,1,m);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int l,r;scanf("%d%d",&l,&r);
rebuild(l,r);
} else {
int l,r;scanf("%d%d",&l,&r);
mat v=segtree::query(1,l,r);
printf("%s\n",(v.a[0]&1)?"Yes":"No");
// v.print();
}
}
return 0;
}
洛谷 P7879 -「SWTR-07」How to AK NOI?(后缀自动机+线段树维护矩乘)的更多相关文章
- 洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)
LOJ BZOJ 洛谷 对这题无话可说,确实比较...裸... 像dls说的拿拓扑和parent树一套就能出出来了... 另外表示BZOJ Rank1 tql... 暴力的话,由每个\(A_i\)向它 ...
- [洛谷P3701]「伪模板」主席树
题目大意:太暴力了,就不写了,看这儿 题解:对于每个$byx$的人,从源点向人连边,容量为此人的寿命. 对于每个手气君的人,从人向汇点连边,容量为此人的寿命. 对于每个$byx$的人与手气君的人,如果 ...
- LOJ 3119: 洛谷 P5400: 「CTS2019 | CTSC2019」随机立方体
题目传送门:LOJ #3119. 题意简述: 题目说的很清楚了. 题解: 记恰好有 \(i\) 个极大的数的方案数为 \(\mathrm{cnt}[i]\),则答案为 \(\displaystyle\ ...
- LOJ 3120: 洛谷 P5401: 「CTS2019 | CTSC2019」珍珠
题目传送门:LOJ #3120. 题意简述: 称一个长度为 \(n\),元素取值为 \([1,D]\) 的整数序列是合法的,当且仅当其中能够选出至少 \(m\) 对相同元素(不能重复选出元素). 问合 ...
- 洛谷P3346 [ZJOI2015]诸神眷顾的幻想乡(广义后缀自动机)
题意 题目链接 Sol 广义SAM的板子题. 首先叶子节点不超过20,那么可以直接对每个叶子节点为根的子树插入到广义SAM中. 因为所有合法的答案一定是某个叶子节点为根的树上的一条链,因此这样可以统计 ...
- 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)
题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...
- 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)
题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...
- 洛谷P4770 [NOI2018]你的名字(后缀自动机+线段树)
传送门 我有种自己根本没学过SAM的感觉……最后还是抄了老半天的题解…… 首先,对$S$和每一次的$T$都建一个SAM 先考虑一下$l=1,r=\left| S \right|$的情况 设$lim_i ...
- 洛谷 P4710 「物理」平抛运动
洛谷 P4710 「物理」平抛运动 洛谷传送门 题目描述 小 F 回到班上,面对自己 28 / 110 的物理,感觉非常凉凉.他准备从最基础的力学学起. 如图,一个可以视为质点的小球在点 A(x_0, ...
随机推荐
- CAM对象样式表
CAM对象样式表 121 160 UF_machining_task_type UF_mach_order_task_subtype 112 UF_machining_null_grp_type 无 ...
- Head First Python 代码和实例下载
http://python.itcarlow.ie/resources.html
- Cobar SQL审计的设计与实现
背景介绍 Cobar简介 Cobar 是阿里开源的一款数据库中间件产品. 在业务高速增长的情况下,数据库往往成为整个业务系统的瓶颈,数据库中间件的出现就是为了解决数据库瓶颈而产生的一种中间层产品. 在 ...
- 【数据结构&算法】04-线性表
目录 前言 线性表的定义 线性表的数据类型&操作 线性表操作 数据类型定义 复杂操作 线性表的顺序存储结构 顺序存储结构的定义 顺序存储方式 数据长度和线性表长度的区别 地址的计算方法 顺序存 ...
- 【性能测试】常见的性能问题分析思路(二)案例&技巧
上一篇介绍了性能问题分析的诊断的基本过程,还没看过的可以先看下[性能测试]常见的性能问题分析思路-道与术,精炼总结下来就是,当遇到性能问题的时候,首先分析现场,然后根据现象去查找对应的可能原因,在通过 ...
- log4j日志集成
一.介绍 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Syslog ...
- 设计模式二--模板方法Template method
模式分类: 书籍推荐:重构-改善既有代码的设计 重构获得模式 设计模式:现代软件设计的特征是"需求的频繁变化".设计模式的要点是 "寻找变化点,然后在变化点处应用设计模式 ...
- Java使用assert断言
Java1.4后新增assert关键字 Idea中开启assert断言 使用 assert boolean表达式 assert boolean表达式 : 错误提示信息 例子 public static ...
- 史上最简单的排序算法?看起来却满是bug
大家好,我是雨乐. 今天在搜论文的时候,偶然发现一篇文章,名为<Is this the simplest (and most surprising) sorting algorithm ever ...
- SQL 添加列,删除列,修改列的类型
alter table 表名 add 列名 数据类型 如:alter table student add nickname char(20) alter table tableName(表名) add ...