一、题目

点此看题

二、解法

今天不知道为什么手感这么好,写一发完全没调就过掉了。

我感觉这种多组询问的字符串题是很难的,经常没有什么思路。我先考虑了一下能不能像 区间本质不同的子串个数 这样直接离线,但我想了很久发现不行的。

正确的做法是很天马行空的,我们 考虑预处理出 \(s\) 的所有子串在 \(t\) 中有没有出现 ,枚举是不可能枚举的,要把他们压在一起快速的处理。设 \(R[i]\) 为 \([i,R[i]]\) 在 \(t\) 中出现过,那么对于比 \(R[i]\) 小的右端点是一定出现过的,比 \(R[i]\) 大的右端点是没有出现过的。

\(R[i]\) 用后缀自动机可以快速处理,因为 \([i,R[i]]\) 是在 \(t\) 中出现过的,\([i+1,R[i]]\) 也是在 \(t\) 中出现过的,那么 \(R[i+1]\geq R[i]\),所以说我们可以暴力跳转移,当发现长度不适应后缀自动机上的这个点时,就可以跳后缀树上的父亲。不难发现时间复杂度是 \(O(n)\) 的。

知道了 \(R[i]\) 之后,询问 \((l,r)\) 的答案很容易写出来:

\[\max_{i=l}^r (\min(R[i],r)-i+1)
\]

这个式子乍看上去没有办法优化,但别忘了我们还有一个法宝:离线 。如果你觉得里面的 \(\min\) 特别恶心那么我们可以分类讨论来去掉这个 \(\min\) :

  • \(R[i]\leq r\),那么里面的柿子就变成了:\(R[i]-i+1\)
  • \(R[i]>r\),那么里面的柿子就变成了:\(r-i+1\)

拆掉 \(\min\) 之后问题变成了二维偏序之类的东西,解决他的固定套路就是 排序降维 。那么我们把 \(R[i],r\) 都从小到大排序,然后维护两颗线段树,一颗维护 \(-i\) 的最大值,一颗维护 \(R[i]-i+1\) 就可以了。

时间复杂度 \(O(n\log n)\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 200005;
const int inf = -1e9;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,k,cnt,last,R[M],ans[M];char s[M],t[M];
int mx[2][4*M];
struct node
{
int fa,len,ch[2];
}a[2*M];
struct reg//regret
{
int l,r,id;
bool operator < (const reg &R) const
{
return r<R.r;
}
}b[M],q[M];
void add(int c)
{
int p=last,np=last=++cnt;
a[np].len=a[p].len;
for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[p].len+1==a[q].len) a[np].fa=q;
else
{
int nq=++cnt;a[nq]=a[q];
a[nq].len=a[p].len+1;
a[np].fa=a[q].fa=nq;
for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
}
}
}
void ins(int i,int l,int r,int id,int v,int f)
{
if(l==r)
{
mx[f][i]=v;
return ;
}
int mid=(l+r)>>1;
if(mid>=id) ins(i<<1,l,mid,id,v,f);
else ins(i<<1|1,mid+1,r,id,v,f);
mx[f][i]=max(mx[f][i<<1],mx[f][i<<1|1]);
}
int ask(int i,int l,int r,int L,int R,int f)
{
if(L>r || l>R) return inf;
if(L<=l && r<=R) return mx[f][i];
int mid=(l+r)>>1;
return max(ask(i<<1,l,mid,L,R,f),ask(i<<1|1,mid+1,r,L,R,f));
}
signed main()
{
scanf("%s %s",s+1,t+1);
n=strlen(s+1);m=strlen(t+1);
cnt=last=1;//attention
for(int i=1;i<=m;i++)
add(t[i]-'a');
for(int i=1,p=1;i<=n;i++)
{
int r=min(i-1,R[i-1]);
if(r==i-1) p=1;
while(p!=1 && a[a[p].fa].len>r-i+1) p=a[p].fa;
while(r<n && a[p].ch[s[r+1]-'a'])
{
r++;
p=a[p].ch[s[r]-'a'];
}
R[i]=r;
b[i]=reg{i,r,0};
}
sort(b+1,b+1+n);
k=read();
for(int i=1;i<=k;i++)
{
int l=read(),r=read();
q[i]=reg{l,r,i};
}
sort(q+1,q+1+k);
memset(mx,-0x3f,sizeof mx);
for(int i=1;i<=n;i++)
ins(1,1,n,i,-i,0);
for(int i=1,j=1;i<=k;i++)
{
int l=q[i].l,r=q[i].r,id=q[i].id;
while(j<=n && b[j].r<=r)
{
ins(1,1,n,b[j].l,inf,0);
ins(1,1,n,b[j].l,b[j].r-b[j].l+1,1);
j++;
}
ans[id]=max(ask(1,1,n,l,r,1),r+ask(1,1,n,l,r,0)+1);
ans[id]=max(0,ans[id]);
}
for(int i=1;i<=k;i++)
printf("%d\n",ans[i]);
}

[BJOI2020] 封印的更多相关文章

  1. 题解 洛谷 P6640 【[BJOI2020] 封印】

    设\(lenth_i\)为\(s\)在\(i\)位置的前缀的后缀为\(t\)的一个子串的最长长度,即为从\(i\)位置开始往前和\(t\)的最长公共子串长度.其可以通过对\(t\)建后缀自动机,然后让 ...

  2. BZOJ2322: [BeiJing2011]梦想封印

    Description 渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解. 为了分析一种奇特的称为梦想封印(Fantasy Seal)的特技,需要引入如下的概念: 每一位魔法的 ...

  3. 「Poetize10」封印一击

    描述 Description Nescafe由n种元素组成(编号为1~n), 第i种元素有一个封印区间[ai,bi].当封印力度E小于ai时,该元素将获得ai的封印能量:当封印力度E在ai到bi之间时 ...

  4. 9102年了,汇总下HttpClient问题,封印一个

    如果找的是core的HttpClientFactory 出门右转. 官方写法,高并发下,TCP连接不能快速释放,导致端口占完,无法连接 Dispose 不是马上关闭tcp连接 主动关闭的一方为什么不能 ...

  5. [BZOJ 2322][BeiJing2011]梦想封印

    梦想封印 题意 原题面: Problem 2322. -- [BeiJing2011]梦想封印 2322: [BeiJing2011]梦想封印 Time Limit: 20 Sec  Memory L ...

  6. 【tyvj】P2065 「Poetize10」封印一击(贪心+线段树/差分)

    http://new.tyvj.cn/p/2065 我就不说我很sb的用线段树来维护值...... 本机自测的时候想了老半天没想出怎么维护点在所有区间被多少区间包含的方法.最后一小时才想出来线段树(果 ...

  7. 简单DP【p1934】封印

    Description 很久以前,魔界大旱,水井全部干涸,温度也越来越高.为了拯救居民,夜叉族国王龙溟希望能打破神魔之井,进入人界"窃取"水灵珠,以修复大地水脉.可是六界之间皆有封 ...

  8. 【BZOJ2322】[BeiJing2011]梦想封印 高斯消元求线性基+DFS+set

    [BZOJ2322][BeiJing2011]梦想封印 Description 渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解. 为了分析一种奇特的称为梦想封印(Fantas ...

  9. 【线性基】bzoj2322: [BeiJing2011]梦想封印

    线性基的思维题+图常见套路 Description 渐渐地,Magic Land上的人们对那座岛屿上的各种现象有了深入的了解. 为了分析一种奇特的称为梦想封印(Fantasy Seal)的特技,需要引 ...

随机推荐

  1. ArcMobile的CoordinateCollection在逆时针添加点时自动调整节点顺序的问题

    为了使用ArcMobile实现量测功能,LZ自定义了一个MapGraphicLayer用于绘图,代码如下: using System.Drawing; using ESRI.ArcGIS.Mobile ...

  2. HDU - 4455 Substrings(非原创)

    XXX has an array of length n. XXX wants to know that, for a given w, what is the sum of the distinct ...

  3. React Hooks: useEffect All In One

    React Hooks: useEffect All In One useEffect https://reactjs.org/docs/hooks-effect.html https://react ...

  4. 动态规划算法 All In One

    动态规划算法 All In One dynamic programming leetcode https://leetcode.com/tag/dynamic-programming/ https:/ ...

  5. Recoil & React official state management

    Recoil & React official state management Redux Recoil.js https://recoiljs.org/ A state managemen ...

  6. How to change Linux Terminal display username

    How to change Linux Terminal display username 如何更改 Linux Terminal 显示的用户名 (base) ➜ ~ whoami xgqfrms-m ...

  7. how to using Linux pipe command output another command's help content to a file

    how to using Linux pipe command output another command's help content to a file Linux tee > >& ...

  8. AI & HR

    AI & HR 数字化人才画像 人力资本数字化管理 通过"AI+数据+专家"的手段,将"数字化人才画像"作为服务起点与信息入口,扩展提供全场景的数字化人 ...

  9. vs code & macOS services

    vs code & macOS services Mac OS X, Open Folder With VS Code (right click) https://github.com/Mic ...

  10. useful tools for programmer programming

    useful tools for programmer programming devtools repl & playground https://repl.it/@xgqfrms/ htt ...