[NOI2018]你的名字

SAM写的太不熟练了~~SAM上的线段树合并也不熟练~~~

调了半天样例

题目大意:

给定一个S,Q次询问,每次给出T,l,r,

求对于S[l,r],属于T的子串却不属于S[l,r]的子串有多少个

看上去挺简洁的一个问题。。。

暴力68pts

对于S[1,n]68pts?

如果做过

 [HEOI2015]最短不公共子串

就好做多了!

可以对A,B分别建SAM

拓扑排序找到A中每个点的后面路径条数。

然后在A上面匹配一遍,如果B匹配不出,直接加上A后面的路径条数

100pts?

刚才的暴力方法实际上不适用了

因为DAG根本无法精确找到[l,r]的部分。。

 

换一个角度

不从图的路径角度考虑子串了

直接从子串定义考虑

 

考虑,对于T,[1,i]这个前缀贡献的答案

假设同一个子串可以算多次的话

把[1,i]这个前缀在S[l,r]中匹配,设最长长度是mx

那么贡献的答案就是i-mx

 

怎么计算"把[1,i]这个前缀在S[l,r]中匹配"得到的最长后缀长度?

用线段树合并维护S的SAM中,点P的right集合

设[1,i-1]匹配的长度为now,匹配在SAM上的点为p

如果p有c出点,出点是x

如果x的right集合中有[l+now,r]区间中一个元素,意味着可以直接匹配下去,得到最长的长度了。break

否则now--,继续尝试。如果now==len[fa[p]],可以更新到更大的集合了,p=fa[p]

设i前缀匹配长度为lim[i]

 upda:2019.3.8:

这个匹配本质上是不断找到当前可能的最长后缀now+'c'在S中所有出现位置,然后看这些出现位置有没有末尾在[l+now,r]的

 

至于相同的子串是1个

那么对T串再建立SAM,用parent树去重,parent树上dfs,每个点的贡献是max(0,min(len[x]-len[fa[x]],len[x]-lim[x]))

相当于把同构的串放在一起,只计算一次

代码

注意,

1.线段树合并还要支持之后的查询

所以必须每次新建节点

类似:CF666E Forensic Examination

2.tot,cnt,num计数器很多别混(懒得namespace了)

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define mid ((l+r)>>1)
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e6+5;
const int M=1e6+5;
int n,q;
char s[N];
int lim[M];
ll ans;
struct SAMSAM{int ch[N][26];int len[N],nd,fa[N];int cnt;void init(){cnt=1,nd=1;}struct tr{int ls,rs;int sum;}t[N*20];int rt[N];int tot;void pushup(int x){t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;}void upda(int &x,int l,int r,int to){x=++tot;if(l==r) {t[x].sum=1;return;}if(to<=mid) upda(t[x].ls,l,mid,to);else upda(t[x].rs,mid+1,r,to);pushup(x);}int merge(int x,int y,int l,int r){//    cout<<" merging "<<x<<" "<<y<<" :: "<<l<<" "<<r<<endl;if(!x||!y) return x+y;int id=++tot;if(l==r){t[id].sum=t[y].sum+t[x].sum;return id;}t[id].ls=merge(t[x].ls,t[y].ls,l,mid);t[id].rs=merge(t[x].rs,t[y].rs,mid+1,r);pushup(id);return id;}void ins(int c,int l){int p=nd;len[nd=++cnt]=l;upda(rt[cnt],1,n,l);for(;p&&ch[p][c]==0;p=fa[p]) ch[p][c]=cnt;//    cout<<"pp "<<p<<" cnt "<<cnt<<" char "<<c<<" ll "<<l<<" : "<<ch[1][c]<<endl;if(!p){fa[cnt]=1;return;}int q=ch[p][c];if(len[q]==len[p]+1){fa[cnt]=q;return;}len[++cnt]=len[p]+1;fa[cnt]=fa[q];fa[q]=fa[nd]=cnt;for(reg j=0;j<26;++j) ch[cnt][j]=ch[q][j];for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=cnt;}struct edge{int nxt,to;}e[2*N];int hd[2*N],num;void add(int x,int y){e[++num].nxt=hd[x];e[num].to=y;hd[x]=num;}void build(){//    cout<<" cnt "<<cnt<<endl;for(reg i=2;i<=cnt;++i){//        cout<<i<<" : fafa "<<fa[i]<<endl;
            add(fa[i],i);}}void dfs(int x){//    cout<<" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx "<<x<<" rt "<<rt[x]<<" sz "<<t[x].sum<<endl;for(reg i=hd[x];i;i=e[i].nxt){int y=e[i].to;dfs(y);rt[x]=merge(rt[x],rt[y],1,n);}}int query(int x,int l,int r,int L,int R){//    cout<<" xx "<<x<<" "<<l<<" and "<<r<<" : query "<<L<<" "<<R<<"  sz "<<t[x].sum<<endl;if(l>r) return 0;if(!x) return 0;if(L<=l&&r<=R) return t[x].sum;int ret=0;if(L<=mid) ret+=query(t[x].ls,l,mid,L,R);if(mid<R) ret+=query(t[x].rs,mid+1,r,L,R);return ret; }
}SAM;
struct samsam{int ch[M][26];int len[M],nd,fa[M];int mx[M];int cnt;void init(){cnt=1,nd=1;}void ins(int c,int l){int p=nd;len[nd=++cnt]=l;mx[cnt]=lim[l];//warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!for(;p&&ch[p][c]==0;p=fa[p]) ch[p][c]=cnt;if(!p){fa[cnt]=1;return;}int q=ch[p][c];if(len[q]==len[p]+1){fa[cnt]=q;return;}len[++cnt]=len[p]+1;fa[cnt]=fa[q];fa[q]=fa[nd]=cnt;for(reg j=0;j<26;++j) ch[cnt][j]=ch[q][j];for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=cnt;}struct edge{int nxt,to;}e[2*N];int hd[2*N],num;void add(int x,int y){e[++num].nxt=hd[x];e[num].to=y;hd[x]=num;}void build(){for(reg i=2;i<=cnt;++i){add(fa[i],i);}}void dfs(int x){////ans ansnsnannsansansna asn ansfor(reg i=hd[x];i;i=e[i].nxt){int y=e[i].to;dfs(y);mx[x]=max(mx[x],mx[y]);}ans+=max(0,min(len[x]-mx[x],len[x]-len[fa[x]]));}void clear(){for(reg i=1;i<=cnt;++i){for(reg j=0;j<26;++j){ch[i][j]=0;}mx[i]=0;len[i]=0;hd[i]=0;fa[i]=0;}num=0;cnt=1;}
}sam;
void clear(){sam.clear();ans=0;
}
int main(){scanf("%s",s+1);n=strlen(s+1);SAM.init();for(reg i=1;i<=n;++i){SAM.ins(s[i]-'a',i);}
//    cout<<" after ins "<<endl;
    SAM.build();
//    cout<<" after build "<<endl;SAM.dfs(1);
//    cout<<" after dfs "<<endl;
    rd(q);int l,r;while(q--){clear();scanf("%s",s+1);rd(l);rd(r);int len=strlen(s+1);int now=0,p=1;for(reg i=1;i<=len;++i){//pipei int c=s[i]-'a';while(1){//            cout<<" cc "<<c<<" "<<SAM.ch[p][c]<<endl;if(SAM.ch[p][c]&&SAM.query(SAM.rt[SAM.ch[p][c]],1,n,l+now,r)){++now;p=SAM.ch[p][c];break;}    if(!now) break;--now;if(now==SAM.len[SAM.fa[p]]) p=SAM.fa[p];}lim[i]=now;//        cout<<" lim "<<i<<" : "<<lim[i]<<" p "<<p<<endl;
        }sam.init();for(reg i=1;i<=len;++i){//insertsam.ins(s[i]-'a',i);}ans=0;sam.build();sam.dfs(1);printf("%lld\n",ans);}return 0;
}}
signed main(){Miracle::main();return 0;
}/*Author: *Miracle*Date: 2019/1/18 17:48:14
*/

总结:

SAM对于公共子串问题一个基本的方法是跑上去匹配

然后下来再考虑每个位置的贡献

parent树、DAG图无形对子串进行了同构的去重

 

转载于:https://www.cnblogs.com/Miracevin/p/10289785.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual.Assist.X.V10.7.1940的汉化破解补丁

Visual Assist X V10.7.1940的汉化破解补丁&#xff0c;方便各位朋友。 从该版本开始&#xff0c;本博客会跟踪升级&#xff0c;请留意。 关于菜单的汉化请看&#xff1a;http://blog.csdn.net/afu45/article/details/9145293 汉化方法 先安装英文原版软件。下载地址&#…

此时无足够的可用内存,无法满足操作的预期要求,可能是由于虚拟地址随便造成的。请稍候重试。 .

vs提示“此时无足够的可用内存&#xff0c;无法满足操作的预期要求&#xff0c;可能是由于虚拟地址随便造成的。请稍候重试。” 下载下面的补丁就可以了 . 下载地址&#xff1a; http://download.csdn.net/detail/afu45/4053280

java目录

阅读目录&#xff1a; 0.Java下载安装1.HelloWorld2.Java语言基础&#xff1a;关键字3.Java语言基础&#xff1a;表示符4.Java语言基础&#xff1a;注释5.Java语言基础&#xff1a;常量和变量6.Java语言基础&#xff1a;运算符7.Java语言基础&#xff1a;语句8.Java语言基础&am…

HDU-2112-HDU Today

这题的话&#xff0c;坑点挺多的&#xff0c;我也WA了好几次。 首先&#xff0c;对于map&#xff0c;因为是多次使用&#xff0c;所以每次处理完一个图之后就要清空。 其次&#xff0c;就是对于DIjkstra跑图的时候&#xff0c;如果这个图是连通图的话&#xff0c;我们每次选取最…

Visual.Assist.X 菜单汉化

在Visual Studio 2010下 使用 Visual.Assist.X.V10.7.1940汉化破解补丁 之后&#xff0c; 细心的朋友会发现&#xff1a;Visual Studio的菜单内还是英文的。其实这个也是可以汉化的&#xff0c;方法如下&#xff1a; 在Microsoft Visual Studio的菜单上右键单击 -》 选择最后…

[vue] 说说你对vue的template编译的理解?

[vue] 说说你对vue的template编译的理解&#xff1f; 将template里的组件编译成虚拟dom个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Visual.Assist.X.V10.7.1946的汉化破解补丁

Visual Assist X V10.7.1946的汉化破解补丁&#xff0c;方便各位朋友。 本博客会跟踪升级&#xff0c;请留意。 关于菜单的汉化请看&#xff1a;http://blog.csdn.net/afu45/article/details/9145293 汉化方法 先安装英文原版软件。下载地址&#xff1a;http://www.wholeto…

[vue] axios是什么?怎样使用它?怎么解决跨域的问题?

[vue] axios是什么&#xff1f;怎样使用它&#xff1f;怎么解决跨域的问题&#xff1f; axios 的是一种异步请求&#xff0c;用法和ajax类似&#xff0c;安装npm install axios --save 即可使用&#xff0c;请求中包括get,post,put, patch ,delete等五种请求方式&#xff0c;解…

iOS 10 之后权限设置

iOS 10 之后权限设置 麦克风权限&#xff1a;Privacy - Microphone Usage Description 是否允许此App使用你的麦克风&#xff1f; 相机权限&#xff1a; Privacy - Camera Usage Description 是否允许此App使用你的相机&#xff1f; 相册权限&#xff1a; Privacy - Photo Libr…

高晓松脱口秀--晓说(第一季第二季)mp3下载

首先推荐一款不错的路由器 399元返399元 相当于 0元购&#xff01; 具体我就不多说了&#xff0c;请点这里 晓说 第一季 (1-5) http://pan.baidu.com/share/link?shareid480859&uk4043605559 (6-10) http://pan.baidu.com/share/link?shareid480864&uk4043605559…

[vue] 你了解axios的原理吗?有看过它的源码吗?

[vue] 你了解axios的原理吗&#xff1f;有看过它的源码吗&#xff1f; 1.axios通过对Promise的封装实现异步请求&#xff1b; 2. if(answer 有){ if(这个问题到此为止){ return ‘有’; }else{ return 没; } }个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放…

android下获取无线wif信号、ssid、MAC等操作类

一个android下获取无线wif信号、ssid、MAC等操作的类。 WifiAdmin.java package com.afu;import java.util.List;import android.content.Context;import android.net.wifi.ScanResult;import android.net.wifi.WifiConfiguration;import android.net.wifi.WifiInfo;import …

[vue] 为何官方推荐使用axios而不用vue-resource?

[vue] 为何官方推荐使用axios而不用vue-resource&#xff1f; 1.vue-resources不再更新了&#xff0c;vue作者尤大推荐axios。 2.axios更加强大 3.axios就是一个基于ES6的Promise的网络请求库&#xff0c;其实说干净了就是一个打包好的XMLHttpRequests&#xff0c;也就是说&am…

Java基础学习-IO流

package IObasics; import java.io.FileWriter; import java.io.IOException;/*IO流* 通过数据流、序列化和文件系统提供系统输入和输出。 * 文件上传&#xff0c;复制文件&#xff0c;下载文件* 输出流&#xff1a;* java.io 类 FileWriter构造方法详细信息 &…

Visual.Assist.X.V10.7.1949的汉化破解补丁

Visual Assist X V10.7.1949的汉化破解补丁&#xff0c;方便各位朋友。 本博客会跟踪升级&#xff0c;请留意。 关于菜单的汉化请看&#xff1a;http://blog.csdn.net/afu45/article/details/9145293 汉化方法 先安装英文原版软件。下载地址&#xff1a;http://www.wholeto…

[vue] 使用vue开发过程你是怎么做接口管理的?

[vue] 使用vue开发过程你是怎么做接口管理的&#xff1f; 创建一个request.js用于封装axios&#xff0c;在 src/api/request&#xff0c;设置拦截器统一处理请求和相应。封装 axios&#xff1a;request.js&#xff1a;import axios from axios import {Message, Loading} from…

金士顿 8G u盘 红色 量产记录

找了好多教程&#xff0c;只有这个成功了&#xff0c;记录下来 逻辑盘符 : H:\ 此分区容量: 7.1G 设备ID : VID 0951 PID 1642 设备序列号: 001CC0EC348CBBB170000294 设备版本 : PMAP 设备制造商: Kingston 设备型号 : DT 101 G2 当…

微信小程序点击跳转出现背景

解决办法&#xff1a; 1、在navigater标签上加上 hover-class“none” 2、在标签css样式中加上backgroud&#xff1a;none&#xff1b; 转载于:https://www.cnblogs.com/weiyunblogs/p/10304045.html

[vue] 如何引入scss?引入后如何使用?

[vue] 如何引入scss&#xff1f;引入后如何使用&#xff1f; 安装scss依赖包&#xff1a; npm install sass-loader --save-dev npm install node-sass --save-dev 在build文件夹下修改 webpack.base.conf.js 文件&#xff1a; 在 module 下的 rules 里添加配置&#xff0c;如…

支付宝手机网站支付 错误代码 insufficient-isv-permissions 错误原因: ISV权限不足

在集成支付宝 手机网站支付 时&#xff0c;明明已经签约了&#xff0c;调用却报错 错误代码 insufficient-isv-permissions 错误原因: ISV权限不足解决办法&#xff1a; 登录开放平台 -> 研发管理-> 我的应用-> 找到对应的应用 点查看-> 功能信息 将里面的手机…