LOJ #6031 字符串
Description

Solution
当 \(k\) 值较小时,发现询问串比较多,串长比较小
然后对 \(Q\) 个询问区间离线跑莫队,一次考虑每一个区间的贡献
假设一个区间 \([i,j]\) 出现的次数是 \(c[i][j]\),然后 \(O(k^2)\) 求出每一个区间的贡献,乘上 \(c[i][j]\) 就是答案
当 \(k\) 值较大时,询问次数比较少,串长比较大
考虑与询问次数有关的做法
对于每一个询问,预处理出 \(w\) 的每一个前缀在 \(S\) 的 \(SAM\) 中匹配到的位置和匹配的长度
右端点固定时,左端点移动形成的串就是这个右端点对应的前缀的后缀,每一次跳父亲就可以跳到
倍增到合法长度的节点即可
显然 \(k\) 取 \(\sqrt{10^5}\) 时最优
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>void gi(T &x){
int f;char c;
for (f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for (x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=2e5+10,M=320,B=20;
int n,m,Q,K,ch[N][26],fa[N],cur=1,cnt=1,len[N],sz[N],sa[N],c[N],g[N];
char s[N];
inline void ins(int c){
int p=cur;cur=++cnt;len[cur]=len[p]+1;
for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=ch[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int nt=++cnt;len[nt]=len[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[q]));
fa[nt]=fa[q];fa[q]=fa[cur]=nt;
for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
}
}sz[cur]=1;
}
inline void priwork(){
for(int i=1;i<=cnt;i++)c[len[i]]++;
for(int i=1;i<=n;i++)c[i]+=c[i-1];
for(int i=cnt;i>=1;i--)sa[c[len[i]]--]=i;
for(int i=cnt;i>=1;i--)sz[fa[sa[i]]]+=sz[sa[i]];
}
struct D{int l,r;}e[N];
struct data{int l,r,id;}q[N];
inline bool comp(data i,data j){return i.l/B!=j.l/B?i.l/B<j.l/B:i.r<j.r;}
namespace solo{
char w[N][M];int v[M][M];ll ans[N];
inline void add(int x){v[e[x].l][e[x].r]++;}
inline void del(int x){v[e[x].l][e[x].r]--;}
inline ll solve(int x){
int len=strlen(w[x]+1),p,c;ll ret=0;
for(int i=1;i<=len;i++){
p=1;
for(int j=i;j<=len;j++){
c=w[x][j]-'a';
if(!ch[p][c])break;
p=ch[p][c];
ret+=v[i][j]*sz[p];
}
}
return ret;
}
void main(){
for(int i=1;i<=Q;i++){
scanf("%s",w[i]+1);
gi(q[i].l);gi(q[i].r);q[i].id=i;q[i].l++;q[i].r++;
}
sort(q+1,q+Q+1,comp);
int l=1,r=0;
for(int i=1;i<=Q;i++){
while(r<q[i].r)add(++r);
while(l>q[i].l)add(--l);
while(r>q[i].r)del(r--);
while(l<q[i].l)del(l++);
ans[q[i].id]=solve(q[i].id);
}
for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
}
}
namespace sol{
char w[N];int pos[N],f[N][20];
inline int qry(int x,int y){
if(len[x]<y)return 0;
for(int i=19;i>=0;i--)
if(f[x][i] && len[f[x][i]]>=y)x=f[x][i];
return sz[x];
}
void main(){
int x,y,le,p,now;
for(int i=1;i<=cnt;i++)f[i][0]=fa[i];
for(int j=1;j<20;j++)
for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=Q;i++){
scanf("%s",w+1);le=strlen(w+1);
p=1;now=0;
for(int j=1;j<=le;j++){
int c=w[j]-'a';
if(ch[p][c])p=ch[p][c],now++;
else{
while(p>1 && !ch[p][c])p=fa[p];
if(ch[p][c])now=len[p]+1,p=ch[p][c];
else now=0;
}
pos[j]=p;g[j]=now;
}
gi(x);gi(y);x++;y++;
ll ret=0;
for(int j=x;j<=y;j++)
if(g[e[j].r]>=e[j].r-e[j].l+1)
ret+=qry(pos[e[j].r],e[j].r-e[j].l+1);
printf("%lld\n",ret);
}
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m>>Q>>K;
scanf("%s",s+1);
for(int i=1;i<=n;i++)ins(s[i]-'a');
priwork();
for(int i=1;i<=m;i++)gi(e[i].l),gi(e[i].r),e[i].l++,e[i].r++;
if(K<M)solo::main();
else sol::main();
return 0;
}
LOJ #6031 字符串的更多相关文章
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- loj 6031「雅礼集训 2017 Day1」字符串
loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...
- loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...
- 【SAM】loj#6401. 字符串
网上有篇题解写的是线段树合并维护求值? 题目描述 有一个只包含小写字母,长度为 $n$ 的字符串 $S$ .有一些字母是好的,剩下的是坏的. 定义一个子串 $S_{l\ldots r}$是好的,当且仅 ...
- 雅礼集训 2017 Day1
T1:loj 6029 市场 题目大意: 维护一个数据结构支持区间加 区间除法 区间求最小值 区间求和 思路: 用线段树维护区间加 区间求最小值 区间和 对于区间除法 注意到除数d很大而加法的w很小 ...
- Contest Record
Contest 1135 at HZOI Problem A: 优美的棋发现一个可以证明的规律就是了……忘记给<<运算的左边变量转化为long long类型了,结果挂了20分……以后一定记 ...
- 【LOJ#3095】[SNOI2019]字符串(后缀数组)
[LOJ#3095][SNOI2019]字符串(后缀数组) 题面 LOJ 题解 首先画图看看如何比较两个串的大小,发现这个东西等价于求两个相邻的后缀的\(LCP\). 一个做法是求出\(SA\),然后 ...
- LOJ 3049: 洛谷 P5284: 「十二省联考 2019」字符串问题
题目传送门:LOJ #3049. 题意简述: 给定一个长度为 \(n\) 的母串 \(S\). 有 \(n_a\) 个 A 类串,都是 \(S\) 的子串,以区间的形式给出. 有 \(n_b\) 个 ...
- LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
题面 LOJ #6436. 「PKUSC2018」神仙的游戏 题解 参考 yyb 的口中的长郡最强选手 租酥雨大佬的博客 ... 一开始以为 通配符匹配 就是类似于 BZOJ 4259: 残缺的字符串 ...
随机推荐
- alpha-咸鱼冲刺day3-紫仪
总汇链接 一,合照 emmmmm.自然还是没有的. 二,项目燃尽图 三,项目进展 今天把数据库的表给建好了,学长那边把登陆跟注册页面也做好了(纯页面,html5+css的那种) 四,问题困难 日常 ...
- numpy.random.seed()方法
先贴参考链接: https://stackoverflow.com/questions/21494489/what-does-numpy-random-seed0-do numpy.random.se ...
- 《Language Implementation Patterns》之 解释器
前面讲述了如何验证语句,这章讲述如何构建一个解释器来执行语句,解释器有两种,高级解释器直接执行语句源码或AST这样的中间结构,低级解释器执行执行字节码(更接近机器指令的形式). 高级解释器比较适合DS ...
- 201621123057 《Java程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 2. 使用数据库技术改造你的系统 2.1 简述如何使用数据库技术改造你的系统.要建立什么表?截图你的表设计. 答 ...
- configparser 练习
[kaixin]xxx = 333name = hahheh = 0[erick]age = 123555xxx = ooo555name = hah555 1 import configparser ...
- prototype 原型链
// 方法1 var aa=function(){ function bb(){ this.name="1111"; console.log(this.name) }; bb.pr ...
- Flask学习 一 基本结构
-from flask import Flask +from flask import Flask,render_template -from flask import request -from f ...
- wpf研究之道——datagrid控件数据绑定
前台: <DataGrid x:Name="TestCaseDataGrid" ItemsSource="{Binding}" > {binding ...
- video与audio的使用
HTML5 DOM 为 <audio> 和 <video> 元素提供了方法.属性和事件. 这些方法.属性和事件允许您使用 JavaScript 来操作 <audio> ...
- Microsoft dynamic 批量更新
//批量处理 ExecuteMultipleRequest multipleRequest = new ExecuteMultipleRequest() { Settings = new Execut ...