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: 残缺的字符串 ...
随机推荐
- Tornado 协程
同步异步I/O客户端 from tornado.httpclient import HTTPClient,AsyncHTTPClient def ssync_visit(): http_client ...
- pandas 数据分析使用
https://github.com/Erick-LONG/data_analysis/blob/master/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%20%E9%8 ...
- nyoj 复杂度
复杂度 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) for(k=j+1;k ...
- nyoj 对决
对决 时间限制:1000 ms | 内存限制:65535 KB 难度:0 描述 Topcoder 招进来了 n 个新同学,Yougth计划把这个n个同学分成两组,要求每组中每个人必须跟另一组中 ...
- 职场选择之大公司 VS 小公司
其实这是个非常难回答的问题,很多职场新人都会有类似的顾虑和疑问. 这个问题就好比业界比较容易引起争议的编程语言哪个是最好的一样.大公司还是小公司里面发展,只有身处其中才能体会,如人饮水,冷暖自知. 笔 ...
- zookeeper入门系列 : 分布式事务
上一章我们了解了zookeeper到底是什么,这一章重点来看zookeeper当初到底面临什么问题?而zookeeper又是如何解决这些问题的? 实际上zookeeper主要就是解决分布式环境下的一致 ...
- node防xss攻击插件
var xss = require('node-xss').clean; router.post("/orders/insert-orders", function (req, r ...
- CURL学习总结(1)
1.curl是什么? 百度百科定义: curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.多种Linux发行版中,并且有DOS和Win32.W ...
- gradle入门(1-7)eclipse和gradle集成插件的安装和使用
一.安装gradle插件:buildship 1.安装插件 gradle默认的本地缓存库在c盘user目录下的.gradle文件夹下,安装好gradle后,可以添加环境变量GRADLE_USER_HO ...
- Oracle 用户创建及权限设置
1:创建临时表空间create temporary tablespace user_temp tempfile 'D:\app\Administrator\oradata\ORACLE\xyrj_t ...