[Tjoi2016&Heoi2016]字符串

[Tjoi2016&Heoi2016]字符串

题目

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CEO,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

INPUT

输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n

OUTPUT

对于每一次询问,输出答案。

SAMPLE

INPUT

5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4

OUTPUT

1

1

2

2

2

解题报告

$SA$+主席树+二分答案

显然这道题直接用$SA$是不太可行的,所以我们可以考虑把他转化成判定性问题,我们二分一个$mid$,判定该长度是否可行

我们考虑$SA$的用法,若两子串有公共前缀,那么两子串中间的$height$必不为$0$

那么用$RMQ$搞出当前可以扩展二分答案出的子串至最长,然后进行查询

显然我们可以将$Rank$扔到主席树中,再去搞查询

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 inline int read(){
 6     int sum(0);
 7     char ch(getchar());
 8     for(;ch<‘0‘||ch>‘9‘;ch=getchar());
 9     for(;ch>=‘0‘&&ch<=‘9‘;sum=sum*10+(ch^48),ch=getchar());
10     return sum;
11 }
12 int n,m,q;
13 char s[100005];
14 int t1[100005],t2[100005],t3[100005],buc[100005];
15 int sa[100005],rank[100005],height[100005],mn[100005][20];
16 inline void Suffix(){
17     int i,j,k(0),p(0),*x(t1),*y(t2),*t;
18     for(i=0;i<=m;++i)buc[i]=0;
19     for(i=1;i<=n;++i)++buc[x[i]=s[i]];
20     for(i=1;i<=m;++i)buc[i]+=buc[i-1];
21     for(i=n;i>=1;--i)sa[buc[x[i]]--]=i;
22     for(j=1;p<n;j<<=1,m=p){
23         for(p=0,i=n-j+1;i<=n;++i)y[++p]=i;
24         for(i=1;i<=n;++i)
25             if(sa[i]>j)
26                 y[++p]=sa[i]-j;
27         for(i=0;i<=m;++i)buc[i]=0;
28         for(i=1;i<=n;++i)t3[i]=x[y[i]];
29         for(i=1;i<=n;++i)++buc[t3[i]];
30         for(i=1;i<=m;++i)buc[i]+=buc[i-1];
31         for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i];
32         for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;++i)
33             x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p;
34     }
35     for(i=1;i<=n;++i)rank[sa[i]]=i;
36     for(i=1;i<=n;height[rank[i++]]=k)
37         for(k?--k:0,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
38 }
39 inline void ST(){
40     for(int i=1;i<=n;++i)
41         mn[i][0]=height[i];
42     for(int i=1;(1<<i)<=n;++i)
43         for(int j=1;j+(1<<i)-1<=n;++j)
44             mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
45 }
46 int cnt;
47 int rt[100005],lch[2000005],rch[2000005],sum[2000005];
48 inline void update(int &x,int las,int pos,int l,int r){
49     x=++cnt;
50 //  cout<<x<<‘ ‘<<las<<‘ ‘<<pos<<‘ ‘<<l<<‘ ‘<<r<<endl;
51     lch[x]=lch[las];
52     rch[x]=rch[las];
53     sum[x]=sum[las]+1;
54     if(l==r)
55         return;
56     int mid((l+r)>>1);
57     if(pos<=mid)
58         update(lch[x],lch[las],pos,l,mid);
59     else
60         update(rch[x],rch[las],pos,mid+1,r);
61 }
62 inline int query(int x,int y,int ll,int rr,int l,int r){
63     if(ll<=l&&r<=rr)
64         return sum[y]-sum[x];
65     int mid((l+r)>>1);
66     if(rr<=mid)
67         return query(lch[x],lch[y],ll,rr,l,mid);
68     if(mid<ll)
69         return query(rch[x],rch[y],ll,rr,mid+1,r);
70     return query(lch[x],lch[y],ll,mid,l,mid)+query(rch[x],rch[y],mid+1,rr,mid+1,r);
71 }
72 int main(){
73     n=read(),q=read(),m=130;
74     scanf("%s",s+1);
75     Suffix();
76     ST();
77     for(int i=1;i<=n;++i)
78         update(rt[i],rt[i-1],rank[i],1,n);
79     while(q--){
80         int a(read()),b(read()),c(read()),d(read());
81         int l(1),r(min(b-a+1,d-c+1)),mid,ans=0;
82         int tp(rank[c]);
83         while(l<=r){
84             mid=(l+r)>>1;
85             int tp1(tp),tp2(tp);
86             for(int i=16;i>=0;--i)
87                 if(tp1>=(1<<i)&&mn[tp1-(1<<i)+1][i]>=mid)
88                     tp1-=(1<<i);
89             for(int i=16;i>=0;--i)
90                 if(tp2+(1<<i)<=n&&mn[tp2+1][i]>=mid)
91                     tp2+=(1<<i);//cout<<l<<‘ ‘<<r<<‘ ‘<<mid<<‘ ‘<<tp1<<" "<<tp2<<endl;
92             if(query(rt[a-1],rt[b-mid+1],tp1,tp2,1,n)>0)
93                 ans=mid,l=mid+1;
94             else
95                 r=mid-1;
96         }
97         printf("%d\n",ans);
98     }
99 }

时间: 2024-09-29 09:25:38

[Tjoi2016&Heoi2016]字符串的相关文章

Bzoj4556: [Tjoi2016&amp;Heoi2016]字符串 后缀数组

4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 169  Solved: 87[Submit][Status][Discuss] Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE O,嫁给高富帅,走上人生巅峰.

[BZOJ4556][TJOI2016&amp;&amp;HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)

4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1360  Solved: 545[Submit][Status][Discuss] Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE O,嫁给高富帅,走上人生巅

[bzoj4556] [Tjoi2016&amp;Heoi2016]字符串

翻转原串,建后缀自动机. 然后先考虑最朴素的思路,找到d所对应的节点,然后一直往上走,并更新答案. 发现由于有a,b的限制,更新答案需要取min,很不爽,不如二分答案. 然后就可以转化为判定性问题,用字符串定位技术找到当前的cd对应的字符串(其实就是倍增+len判定), 判定当前的节点是否有当前a,b范围的right集. 要知道每个节点的right集具体是什么用dfs序建立主席树即可. #include<iostream> #include<cstdio> #include<

bzoj4556: [Tjoi2016&amp;Heoi2016]字符串 (后缀数组加主席树)

题目是给出一个字符串,每次询问一个区间[a,b]中所有的子串和另一个区间[c,d]的lcp最大值,首先求出后缀数组,对于lcp的最大值肯定是rank[c]的前驱和后继,但是对于这个题会出现问题,就是题目中有区间的限制. For example: 5 1 aaaab 1 2 3 5 对于这个样例,如果直接找到aab的前驱是 aaab,然后由于区间的原因答案是1,但是如果我们再往前找的话,找到aaaab,答案会变成2.那就出现了错误.考虑一下怎么做可以去除这种影响呢? 我们可以二分一下,首先对于[a

bzoj 4556: [Tjoi2016&amp;Heoi2016]字符串

二分ans,二分区间长度,st表查,最后主席树判断. 这题最大收获学到了一个nb的卡常技巧,主席树元素个数为0直接返回,不敢相信快了一倍. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200005 6 using namespace std; 7 inline int read() 8 { 9 int p=0;cha

[TJOI2016 &amp; HEOI2016] 字符串

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4556 [算法] 不难发现 , 对于每个询问        ans = max{ min{b - i + 1 , lcp(i , c) } (a <= i <= b) 不妨二分答案mid , 那么问题就转化为求 max{ lcp(i  , c) } (a <= i <= b - mid + 1) 而我们知道 , 所有lcp(i , j) <= k的i是连续的一段区

bzoj4556【TJOI2016&amp;HEOI2016】字符串

4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 195  Solved: 103 [Submit][Status][Discuss] Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE O,嫁给高富帅,走上人生

BZOJ 4553 Tjoi2016&amp;Heoi2016 序列

Tjoi2016&Heoi2016序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你 ,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 .注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1 1 31 2 4

bzoj4551[Tjoi2016&amp;Heoi2016]树

bzoj4551[Tjoi2016&Heoi2016]树 题意: 给个根节点为1的n点树,初始时节点1标记,Q个操作,每次可以标记一个点或求一个点最近一个标记了的祖先. 题解: 链剖可以写,当正解应该是并查集.离线读入所有操作,累加每个节点的标记次数,之后所有未被标记的节点向其父亲节点连边,然后倒着来,如果操作是询问则输出这个节点在并查集中的根节点,如果是标记则将该节点的标记数减1,一旦这个节点的标记数减到了0,就让它向父亲节点连边. 代码: 1 #include <cstdio> 2