BZOJ1396:识别子串(后缀自动机+单调队列)
2018-03-14 20:13
344 查看
题面
题意:给出一个串串,对于每个位置
求包含每个位置的,最短的,只出现一次的子串的长度
由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]f[L]
显然ff单调不降
在后缀自动机上,考虑Right
4000
集大小为1的状态T
发现f[1]到f[dep[T]−Min(T)+1]f[1]到f[dep[T]−Min(T)+1]可用dep[T]更新
对于每个位置i,考虑以它为右端点
找到第一个f[h]<if[h]<i的h,i-h+1可更新ans[i]
若不以其为右端点,则j∈[h+1,i]j∈[h+1,i]的f[j]−j+1f[j]−j+1可更新ans[i]
单调队列维护即可
zenzen不用线段树哦
题意:给出一个串串,对于每个位置
求包含每个位置的,最短的,只出现一次的子串的长度
由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]f[L]
显然ff单调不降
在后缀自动机上,考虑Right
4000
集大小为1的状态T
发现f[1]到f[dep[T]−Min(T)+1]f[1]到f[dep[T]−Min(T)+1]可用dep[T]更新
对于每个位置i,考虑以它为右端点
找到第一个f[h]<if[h]<i的h,i-h+1可更新ans[i]
若不以其为右端点,则j∈[h+1,i]j∈[h+1,i]的f[j]−j+1f[j]−j+1可更新ans[i]
单调队列维护即可
zenzen不用线段树哦
#include <iostream> #include <fstream> #include <algorithm> #include <cmath> #include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define mmst(a, b) memset(a, b, sizeof(a)) #define mmcp(a, b) memcpy(a, b, sizeof(b)) typedef long long LL; const int N=400200,oo=1e9+7; int n; int pre ,dep ,r ,son [26],cnt=1,last=1; int head ,nex ,to ,cur; int len ,ans ,q ; char s ; void add(int u,int v) { to[++cur]=v; nex[cur]=head[u]; head[u]=cur; } void dfs(int x) { for(int h=head[x];h;h=nex[h]) dfs(to[h]),r[x]+=r[to[h]]; } void Insert(int x) { dep[++cnt]=dep[last]+1; int np=cnt,p=last; last=cnt; r[np]=1; for(;!son[p][x];p=pre[p]) son[p][x]=np; if(!p) pre[np]=1; else { int q=son[p][x]; if(dep[q]==dep[p]+1) pre[np]=q; else { dep[++cnt]=dep[p]+1; int nq=cnt; pre[nq]=pre[q]; pre[q]=pre[np]=nq; mmcp(son[nq],son[q]); for(;son[p][x]==q;p=pre[p]) son[p][x]=nq; } } } int main() { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;i++) Insert(s[i]-'a'); for(int i=2;i<=cnt;i++) add(pre[i],i); dfs(1); for(int i=1;i<=n;i++) ans[i]=len[i]=oo; for(int i=2;i<=cnt;i++) if(r[i]==1) len[dep[i]-dep[pre[i]]]=min(len[dep[i]-dep[pre[i]]],dep[i]); for(int i=n-1;i>=1;i--) len[i]=min(len[i],len[i+1]); int now aa04 =n,hh=1,tt=0; for(int i=n;i>=1;i--) { while(now>=1&&len[now]>i) { while(hh<=tt&&len[q[tt]]-q[tt]>=len[now]-now) tt--; if(len[now]!=oo&&now<=i) q[++tt]=now; now--; } if(now) ans[i]=min(ans[i],i-now+1); if(hh<=tt) ans[i]=min(ans[i],len[q[hh]]-q[hh]+1); if(q[hh]==i) hh++; } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)
- 【BZOJ-1396&2865】识别子串&字符串识别 后缀自动机/后缀树组 + 线段树
- BZOJ 1396:识别子串 SA+树状数组+单调队列
- bzoj 1396: 识别子串 (后缀自动机+线段树)
- [BZOJ1396]识别子串 后缀自动机+线段树
- 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
- [BZOJ1396]识别子串(后缀自动机+线段树)
- 【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)
- BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
- [后缀自动机 线段树] BZOJ 1396 识别子串 & BZOJ 2865 字符串识别
- [后缀自动机][单调队列优化DP] BZOJ 2806: [Ctsc2012]Cheat
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
- BZOJ 2806: [Ctsc2012]Cheat 后缀自动机+单调队列优化DP
- [二分 后缀自动机 单调队列优化DP] BZOJ 2806 [Ctsc2012]Cheat
- 【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
- 【BZOJ2806】Cheat(后缀自动机,二分答案,动态规划,单调队列)
- bzoj 2806 [Ctsc2012]Cheat 后缀自动机 单调队列优化dp