题解

把S串建一个后缀自动机

用一个可持久化权值线段树维护每个节点的right集合是哪些节点

求本质不同的子串我们就是要求T串中以每个点为结束点的串有多少在\(S[l..r]\)中出现过

首先我们需要对于T串每个点本身和自己的匹配长度,可以建一个后缀自动机来完成

然后把T串放在S串上跑匹配,匹配到下一个点x时,匹配的长度是len,如果x所在的right集合在\([l + len - 1,r]\)中没有,那么就不合法,把长度减少,如果长度减少到和父亲节点的长度一样,则需要把当前节点跳到父亲节点上

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <random>
#include <ctime>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
char s[MAXN],t[MAXN];
int N,Q,val[MAXN];
int64 ans[MAXN];
struct tr_node {
int lc,rc;
}tr[MAXN * 40];
int Ncnt,rt[MAXN * 2];
int Find(int u,int l,int r,int ql,int qr) {
if(!u) return -1;
if(l > qr || r < ql) return -1;
if(l == r) return l;
int mid = (l + r) >> 1;
int res = Find(tr[u].rc,mid + 1,r,ql,qr);
if(res == -1) res = Find(tr[u].lc,l,mid,ql,qr);
return res;
}
void Insert(int &u,int v,int l,int r,int p) {
u = ++Ncnt;
tr[u] = tr[v];
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) Insert(tr[u].lc,tr[v].lc,l,mid,p);
else Insert(tr[u].rc,tr[v].rc,mid + 1,r,p);
}
int Merge(int u,int v) {
if(!u || !v) return u + v;
int res = ++Ncnt;
tr[res].lc = Merge(tr[u].lc,tr[v].lc);
tr[res].rc = Merge(tr[u].rc,tr[v].rc);
return res;
}
int que[MAXN * 2],c[MAXN];
struct sam {
struct node {
int par,len,nxt[26],cnt;
}tr[MAXN * 2];
int tail,root,last; void Init() {
tail = 0;
root = last = ++tail;
memset(tr[tail].nxt,0,sizeof(tr[tail].nxt));
tr[tail].par = tr[tail].len = 0;
}
void build(int c) {
int nw = ++tail,p;
memset(tr[nw].nxt,0,sizeof(tr[nw].nxt));
tr[nw].len = tr[last].len + 1;tr[nw].cnt = 1; for(p = last ; p && !tr[p].nxt[c] ; p = tr[p].par) {
tr[p].nxt[c] = nw;
}
if(!p) tr[nw].par = root;
else {
int q = tr[p].nxt[c];
if(tr[q].len == tr[p].len + 1) tr[nw].par = q;
else {
int cq = ++tail;
tr[cq] = tr[q];tr[cq].cnt = 0;
tr[cq].len = tr[p].len + 1;
tr[nw].par = tr[q].par = cq;
for(;p && tr[p].nxt[c] == q ; p = tr[p].par) {
tr[p].nxt[c] = cq;
}
}
}
last = nw;
}
void calc() {
for(int i = 1 ; i <= tail ; ++i) c[tr[i].len]++;
for(int i = 1 ; i <= N ; ++i) c[i] += c[i - 1];
for(int i = 1 ; i <= tail ; ++i) {
que[c[tr[i].len]--] = i;
}
for(int i = tail ; i >= 1 ; --i) {
int u = que[i];
if(tr[u].cnt) Insert(rt[u],rt[u],1,N,tr[u].len);
int f = tr[u].par;
rt[f] = Merge(rt[f],rt[u]);
}
}
}sam[2];
bool check(int p,int l,int r,int c) {
int t = Find(rt[p],1,N,l,r);
if(t == -1) return false;
return (t - l + 1) >= c;
}
void Solve() {
scanf("%s",s + 1);
N = strlen(s + 1);
read(Q);
sam[0].Init();
for(int i = 1 ; i <= N ; ++i) {
sam[0].build(s[i] - 'a');
}
sam[0].calc();
int l,r,len;
for(int i = 1 ; i <= Q ; ++i) {
scanf("%s",t + 1);
read(l);read(r);
len = strlen(t + 1);
sam[1].Init();
for(int j = 1 ; j <= len ; ++j) {
sam[1].build(t[j] - 'a');
int f = sam[1].tr[sam[1].last].par;
val[j] = sam[1].tr[f].len;
}
int p = sam[0].root,c = 0;
for(int j = 1 ; j <= len ; ++j) {
int h = t[j] - 'a';
while(p && !sam[0].tr[p].nxt[h]) {
p = sam[0].tr[p].par;
c = sam[0].tr[p].len;
}
if(!sam[0].tr[p].nxt[h]) {
c = 0;p = sam[0].root;
}
else {
p = sam[0].tr[p].nxt[h];++c;
while(!check(p,l,r,c)) {
--c;
int f = sam[0].tr[p].par;
if(c == sam[0].tr[f].len) p = f;
}
}
val[j] = max(val[j],c);
ans[i] += j - val[j];
}
} for(int i = 1 ; i <= Q ; ++i) {
out(ans[i]);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#else
freopen("name.in","r",stdin);
freopen("name.out","w",stdout);
#endif
Solve();
return 0;
}

【LOJ】#2720. 「NOI2018」你的名字的更多相关文章

  1. LOJ 2720 「NOI2018」你的名字——后缀自动机

    题目:https://loj.ac/problem/2720 自己总是分不清 “SAM上一个点的 len[ ] ” 和 “一个串的前缀在 SAM 上匹配的 len ”. 于是原本想的 68 分做法是, ...

  2. loj#2720. 「NOI2018」你的名字

    链接大合集: loj uoj luogu bzoj 单纯地纪念一下写的第一份5K代码.../躺尸 因为ZJOI都不会所以只好写NOI的题了... 总之字符串题肯定一上来就拼个大字符串跑后缀数组啦! ( ...

  3. LOJ_#2720. 「NOI2018」你的名字 _后缀数组+主席树+倍增

    题面: https://loj.ac/problem/2720 考虑枚举T串的每个后缀i,我们要做两件事. 一.统计有多少子串[i,j]在S中要求位置出现. 二.去重. 第二步好做,相当于在后缀数组上 ...

  4. 「NOI2018」你的名字

    「NOI2018」你的名字 题目描述 小A 被选为了\(ION2018\) 的出题人,他精心准备了一道质量十分高的题目,且已经 把除了题目命名以外的工作都做好了. 由于\(ION\) 已经举办了很多届 ...

  5. LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)

    题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...

  6. loj#2718. 「NOI2018」归程

    题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...

  7. loj#2721. 「NOI2018」屠龙勇士

    题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...

  8. Loj #2719. 「NOI2018」冒泡排序

    Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...

  9. loj 2719 「NOI2018」冒泡排序 - 组合数学

    题目传送门 传送门 题目大意 (相信大家都知道) 显然要考虑一个排列$p$合法的充要条件. 考虑这样一个构造$p$的过程.设排列$p^{-1}_{i}$满足$p_{p^{-1}_i} = i$. 初始 ...

随机推荐

  1. 为http请求追加cookie值

    1.html中引入JQuery Cookie插件. 2.JS var expiresTime = new Date(); expiresTime.setTime(expiresTime.getTime ...

  2. 一个Maven项目在eclipse中正常,但在IDEA中启动时报错

    这个项目十有八九最初是在ecplise创建的,框架上十有八九整合了Mybatis,报的错误十有八九是 org.apache.ibatis.binding.BindingException: Inval ...

  3. 【MongoDB】查询字段对应的数组中包含某个值

    在MongoDB操作的时候,我们可能会遇到查询[字段对应的数组中包含某个值]的数据,查询语句如下,假设表名为user. 示例1 数据 { id: 1, state_arr: [ "123&q ...

  4. ansible 主机正则

    ansible <pattern> -m <module_name> -a <arguments> 该功能主要针对Inventory的主机列表,案例如下: 1.AL ...

  5. [RK3399] 虚拟按键栏显示不全或者方向不对

    CPU:RK3399 系统:Android 7.1 同样的系统代码,换了一个小分辨率的屏,虚拟按键栏就出现显示不全,而且方向不对 出现这种问题的原因是显示密度和屏不匹配,需要适当的降低显示密度即可 d ...

  6. php发现一个神奇的函数

    echo strtr('aaddffvvbbcc','avc','242'); //22ddff44bb22 echo '<br>'; echo str_replace('ad',22,' ...

  7. uboot移植spi驱动

    记录一下在uboot内移植spi驱动的过程 芯片:freescale Mpc8308 uboot版本:u-boot-2009.11-rc1.2 需求:我们需要在uboot下通过spi配置一个时钟芯片( ...

  8. JAVA关于静态static的面试题

    JAVA关于静态static的面试题     版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net ...

  9. NetHogs监控Linux的每个进程流量

    在日常运维环境中,我们肯定会遇到以下这种需求: 1.网络流量异常,不知道是哪个程序的流量爆涨? 2.日常需要监控网络实时的流量进去数据 面试装逼系列|这篇文章,让运维监控不再成为你的短板! 学会这 1 ...

  10. spring boot配置文件、日志配置和代码的多环境配置

    一般项目都逃不掉开发.测试和生产这三套环境,如果每次给这三套环境打包都去改配置,累死不说,还一不留心就出差错.倒不如每套环境各给一套配置来的轻松.上代码: 1.通用配置放在application.pr ...