HEOI2016/TJOI2016 字符串问题
题目链接:戳我
非常不好意思,因为想要排版,所以今天先只把代码贴出来,明天补题解。
40pts暴力:直接暴力匹配
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 100010
using namespace std;
int n,m;
char s[MAXN];
inline int solve(int l1,int r1,int l2,int r2)
{
int cur_ans=0,maxx=0;
for(int i=l1;i<=r1;i++)
{
if(s[i]==s[l2+cur_ans]) cur_ans++;
else cur_ans=0;
maxx=max(maxx,cur_ans);
// printf("i=%d cur_ans=%d\n",i,cur_ans);
if(cur_ans>=r2-l2+1) break;
}
return maxx;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=m;i++)
{
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
printf("%d\n",solve(l1,r1,l2,r2));
}
return 0;
}
开O2才能A的正解:SA+二分+二分+主席树
复杂度是两只log的。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 200010
using namespace std;
int n,m,p,tot;
int sa[MAXN],rnk[MAXN],tax[MAXN],tp[MAXN];
int lg[MAXN],h[MAXN],rt[MAXN],st[MAXN][18];
char s[MAXN];
struct Node{int ls,rs,ff,cnt;}t[MAXN<<4];
inline void build(int &x,int f,int l,int r,int k)
{
x=++tot;
t[x]=t[f];
t[x].cnt++;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) build(t[x].ls,t[f].ls,l,mid,k);
else build(t[x].rs,t[f].rs,mid+1,r,k);
}
inline int query(int x,int f,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return t[x].cnt-t[f].cnt;
int mid=(l+r)>>1,cur_ans=0;
if(ll<=mid) cur_ans+=query(t[x].ls,t[f].ls,l,mid,ll,rr);
if(mid<rr) cur_ans+=query(t[x].rs,t[f].rs,mid+1,r,ll,rr);
return cur_ans;
}
inline void q_sort()
{
for(int i=1;i<=m;i++) tax[i]=0;
for(int i=1;i<=n;i++) tax[rnk[i]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=n;i>=1;i--) sa[tax[rnk[tp[i]]]--]=tp[i];
}
inline void suffix_sort()
{
m=50,p=0;
for(int i=1;i<=n;i++) rnk[i]=s[i]-'a'+1,tp[i]=i;
q_sort();
for(int w=1;p<n;m=p,w<<=1)
{
p=0;
for(int i=1;i<=w;i++) tp[++p]=n+i-w;
for(int i=1;i<=n;i++) if(sa[i]-w>0) tp[++p]=sa[i]-w;
q_sort();
swap(rnk,tp);
p=rnk[sa[1]]=1;
for(int i=2;i<=n;i++)
rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
}
}
inline void get_h()
{
int j,k=0;
for(int i=1;i<=n;i++)
{
if(k) k--;
int j=sa[rnk[i]-1];
while(s[i+k]==s[j+k]) k++;
h[rnk[i]]=k;
}
}
inline void st_init()
{
for(int i=1;i<=n;i++) st[i][0]=h[i];
for(int j=1;j<=17;j++)
for(int i=1;i<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int st_query(int l,int r)
{
if(l==r) return 0x3f3f3f3f;
l++;
return min(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]);
}
inline bool check(int x,int l1,int r1,int l2,int r2)
{
int L,R,l=1,r=rnk[l2],ans=r;
while(l<=r)
{
int mid=(l+r)>>1;
if(st_query(mid,rnk[l2])>=x) ans=mid,r=mid-1;
else l=mid+1;
}
L=ans;
l=rnk[l2],r=n,ans=l;
while(l<=r)
{
int mid=(l+r)>>1;
if(st_query(rnk[l2],mid)>=x) ans=mid,l=mid+1;
else r=mid-1;
}
R=ans;
return query(rt[R],rt[L-1],1,n,l1,r1-x+1)==0?false:true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
suffix_sort();
get_h();
st_init();
for(int i=1;i<=n;i++) build(rt[i],rt[i-1],1,n,sa[i]);
for(int i=1;i<=m;i++)
{
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
int ans=0;
int l=0,r=min(r1-l1,r2-l2)+1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid,l1,r1,l2,r2)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}
HEOI2016/TJOI2016 字符串问题的更多相关文章
- BZOJ 4556 [HEOI2016/TJOI2016]字符串
BZOJ 4556 [HEOI2016/TJOI2016]字符串 其实题解更多是用后缀数组+数据结构的做法,貌似也不好写. 反正才学了 sam 貌似比较简单的做法. 还是得先二分,然后倍增跳到 $ s ...
- P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案
$ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...
- [HEOI2016/TJOI2016]字符串
嘟嘟嘟 今天复习一下SAM. lcp固然不好做,干脆直接翻过来变成后缀.首先答案一定满足单调性,所以我们二分lcp的长度\(mid\),然后判断\(s[d \ldots d + mid - 1]\)是 ...
- [HEOI2016/TJOI2016]字符串(后缀数组+二分+主席树/后缀自动机+倍增+线段树合并)
后缀数组解法: 先二分最长前缀长度 \(len\),然后从 \(rnk[c]\) 向左右二分 \(l\) 和 \(r\) 使 \([l,r]\) 的 \(height\geq len\),然后在主席树 ...
- 【[HEOI2016/TJOI2016]字符串】
码农题啊 上来先无脑一个\(SA\)的板子,求出\(SA\)和\(het\)数组 我们只需要从\(sa[i]\in[a,b]\)的所有\(i\)中找到一个\(i\)使得\(sa[i]\)和\(rk[c ...
- luoguP4094 [HEOI2016/TJOI2016]字符串
题意 考虑二分答案\(mid\),现在我们要判断\(s[c...c+mid-1]\)是否在\(s[a...b]\)出现过. 首先找到\(s[c...c+mid-1]\)所在的状态: 建出\(paren ...
- BZOJ4556 HEOI2016/TJOI2016字符串 (后缀树+主席树)
二分答案后相当于判断一个区间的后缀与某个后缀的最长公共前缀是否能>=ans.建出后缀树,在上述问题中后者所在节点向上倍增的跳至len>=ans的最高点,然后相当于查询子树中是否有该区间的节 ...
- 洛谷 P4094 [HEOI2016/TJOI2016]字符串(SA+主席树)
题面传送门 一道码农题---- u1s1 感觉这类题目都挺套路的,就挑个有代表性的题写一篇题解罢. 首先注意到答案满足可二分性,故考虑二分答案 \(mid\),转化为判定性问题. 考虑怎样检验 \(m ...
- cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )
hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...
随机推荐
- 从入门到自闭之Python函数初识
函数初识 定义:def--关键字 将某个功能封装到一个空间中就是一个函数 功能: 减少重复代码 函数的调用 函数名+():调用函数和接收返回值 函数的返回值 return 值 == 返回值 ...
- python网络编程——使用UDP、TCP协议收发信息
UDP UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送. UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内. UDP ...
- python 变量 (全面不一样的变量)
变量 一:什么是变量? 变量即变化的量,核心是"变"与"量"二字,变即变化,量即衡量状态 变:状态是会发生改变的 量:记录现实世界中的状态,让计算机能够像人一样 ...
- spark教程(九)-操作数据库
数据库也是 spark 数据源创建 df 的一种方式,因为比较重要,所以单独算一节. 本文以 postgres 为例 安装 JDBC 首先需要 安装 postgres 的客户端驱动,即 JDBC 驱动 ...
- Linux-1.2关机重启reboot,shutdown
关机重启:reboot,shutdown reboot 重启操作系统 shutdown -r now 重启,shutdown会给其他用户提示
- maven引用本地jar,并打包部署
由于项目需要的一个jar在maven仓库里没有,又不想把jar手动导入仓库.然而百度的几个处理方式都是一样的方法,我却没有一个成功的.于是就请教了大神,大神也是各种测试,终于成功实现了,实现如下: 新 ...
- ArrayList扩容分析
一段java代码 String e = "q3234v"; List<String> list = new ArrayList<String>(); for ...
- HTML和CSS学习
HTML和CSS HTML 基础讲解 要点: 标记语言不是编程语言 .html和.htm都是html文档的后缀 标签有围堵和自闭两类 开始标签中可以定义属性,属性的值要用引号引起来 H5一般用于移动端 ...
- python之json操作
1.json.dumps()用于将dict类型的数据转成str 备注:文件路径前面加上 r 是为了避免转义 1 import json 2 3 dict = {'a': 'wo', 'b': 'zai ...
- js之运算符(逻辑运算符)
逻辑运算符通常用于布尔型(逻辑)值.这种情况下,它们返回一个布尔值.它经常和关系运算符一起配合使用.“&&” .“!”和“ ||” 运算符会返回一个指定操作数的值,因此,这些运算符也用 ...