并不对劲的Loj6031:「雅礼集训 2017 Day1」字符串
题目传送门:->
看到题目的第一反应当然是暴力:对于串s建后缀自动机,每次询问中,求w对应的子串在s的SAM中的right集合。O(qmk)听上去显然过不了。
数据范围有个∑w<=1e5,也就是说,q*k<=1e5,当q更小或k更小时可以用不同的方法。
k更小时,会发现每个w的子串数可能会很小,子串数可能还没m多。这个时候将m个[li,ri]的询问可能会有重复的,所以可以用vector存一下对于每一个[L,R],满足li=L且ri=R的询问的编号是哪些。求出w对于每个[L,R]有多少个满足li=L且ri=R的询问的编号在[a,b](可以用vector自带的lower_bound),和w[L,R]在s中的出现次数。这样,时间复杂度是O(q*log m*k2)。
q更小时,对于每个w可以求出它的每个[1,i]的前缀会匹配到s的SAM的哪个点(记作pla[i])、能匹配s多长。SAM中的每个点的fail指针指向的点都是它的后缀。所以对于每个w[li,ri],可以先走到pla[ri],再倍增地顺着fail指针走。时间复杂度是O(q*m*log k)。
听说代码很难调?
#include <bits/stdc++.h>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define re register
#define LL long long
#define maxn 200010
#define block 333
using namespace std;
inline LL read()
{
LL x=0,f=1;
char ch=getchar();
while(isdigit(ch)==0 && ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(LL x)
{
LL f=0;char ch[20];
if(!x){puts("0");return;}
if(x<0){putchar('-');x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
int ch[maxn][30],dis[maxn],ord[maxn],c[maxn],fa[maxn],cnt,rt,lst,anc[maxn][21];
int n,m,q,k,ql[maxn],qr[maxn],pla[maxn],lth[maxn];
LL r[maxn];
vector<int>to[block][block];
char s[maxn],w[maxn];
int gx(char c){return c-'a';}
void go(int & u,int & len, int x)
{
while(!ch[u][x]&&u)u=fa[u],len=dis[u];
if(ch[u][x])u=ch[u][x],++len;
else u=rt,len=0;
}
void extend(LL pos)
{
int x=gx(s[pos]),p=lst,np=++cnt;lst=np;dis[np]=pos;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=rt;
else
{
LL q=ch[p][x];
if(dis[q]==dis[p]+1)fa[np]=q;
else
{
LL nq=++cnt;dis[nq]=dis[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;p&&ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
}
void getr()
{
for(int u=rt,i=1;i<=n;++i)u=ch[u][gx(s[i])],++r[u];
rep(i,1,cnt)c[dis[i]]++;
rep(i,1,n)c[i]+=c[i-1];
rep(i,1,cnt)ord[c[dis[i]]--]=i;
dwn(i,cnt,1)r[fa[ord[i]]]+=r[ord[i]];
}
void getfa(){rep(l,1,cnt){int i=ord[l];anc[i][0]=fa[i];rep(j,1,20)anc[i][j]=anc[anc[i][j-1]][j-1];}}
int main()
{
lst=rt=++cnt;
n=read(),m=read(),q=read(),k=read();
scanf("%s",s+1);
rep(i,1,n)extend(i);getr();
rep(i,1,m){ql[i]=read()+1,qr[i]=read()+1;if(k<=block)to[ql[i]][qr[i]].push_back(i);}
if(k<=block)
{
while(q--)
{
scanf("%s",w+1);
int a=read()+1,b=read()+1;LL ans=0;
rep(i,1,k)
{
int u=rt;
rep(j,i,k)
{
if(ch[u][gx(w[j])])
{
u=ch[u][gx(w[j])];
vector<int>::iterator L=lower_bound(to[i][j].begin(),to[i][j].end(),a);
vector<int>::iterator R=upper_bound(to[i][j].begin(),to[i][j].end(),b);
ans+=(R-L)*r[u];
}
else break;
}
}
write(ans);
}
}
else
{
getfa();
while(q--)
{
scanf("%s",w+1);
int a=read()+1,b=read()+1;LL ans=0;
for(int len=0,u=rt,i=1;i<=k;i++)go(u,len,gx(w[i])),lth[i]=len,pla[i]=u;
rep(i,a,b)
{
if(lth[qr[i]]<qr[i]-ql[i]+1)continue;
else
{
int u=pla[qr[i]];
dwn(j,19,0)if(dis[anc[u][j]]>=qr[i]-ql[i]+1)u=anc[u][j];
ans+=r[u];
}
}
write(ans);
}
}
return 0;
}
并不对劲的Loj6031:「雅礼集训 2017 Day1」字符串的更多相关文章
- loj6031「雅礼集训 2017 Day1」字符串
题目 首先先对\(s\)建一个\(\operatorname{SAM}\),设\(w=kq\) 发现\(k,q\leq 10^5\),但是\(w\leq 10^5\),于是套路地根号讨论一下 如果\( ...
- [LOJ 6031]「雅礼集训 2017 Day1」字符串
[LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...
- loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
题意 链接 Sol \(10^5\)次询问每次询问\(10^5\)个区间..这种题第一感觉就是根号/数据分治的模型. \(K\)是个定值这个很关键. 考虑\(K\)比较小的情况,可以直接暴力建SAM, ...
- 「雅礼集训 2017 Day1」字符串 SAM、根号分治
LOJ 注意到\(qk \leq 10^5\),我们很不自然地考虑根号分治: 当\(k > \sqrt{10^5}\),此时\(q\)比较小,与\(qm\)相关的算法比较适合.对串\(s\)建S ...
- loj 6031「雅礼集训 2017 Day1」字符串
loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...
- 「雅礼集训 2017 Day1」 解题报告
「雅礼集训 2017 Day1」市场 挺神仙的一题.涉及区间加.区间除.区间最小值和区间和.虽然标算就是暴力,但是复杂度是有保证的. 我们知道如果线段树上的一个结点,\(max=min\) 或者 \( ...
- [LOJ 6030]「雅礼集训 2017 Day1」矩阵
[LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...
- [LOJ 6029]「雅礼集训 2017 Day1」市场
[LOJ 6029] 「雅礼集训 2017 Day1」市场 题意 给定一个长度为 \(n\) 的数列(从 \(0\) 开始标号), 要求执行 \(q\) 次操作, 每次操作为如下四种操作之一: 1 l ...
- loj#6030. 「雅礼集训 2017 Day1」矩阵(贪心 构造)
题意 链接 Sol 自己都不知道自己怎么做出来的系列 不难观察出几个性质: 最优策略一定是先把某一行弄黑,然后再用这一行去覆盖不是全黑的列 无解当且仅当无黑色.否则第一个黑色所在的行\(i\)可以先把 ...
随机推荐
- POJ1780 Code
KEY公司开发出一种新的保险箱.要打开保险箱,不需要钥匙,但需要输入一个正确的.由n位数字组成的编码.这种保险箱有几种类型,从给小孩子玩的玩具(2位数字编码)到军用型的保险箱(6位数字编码).当正确地 ...
- [luoguP2704] 炮兵阵地(状压DP)
传送门 可以事先把每一行的所有状态处理出来,发现每一行的状态数最多不超过60个 f[i][j][k]表示前i行,第i行为状态j,第i-1行为状态k的最优解 #include <vector> ...
- 洛谷P1244 青蛙过河
P1244 青蛙过河 362通过 525提交 题目提供者该用户不存在 标签 难度普及- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 题目什么意思 题目看不懂啊 题目描述 有一条河 ...
- 博弈 Nim问题 POJ2234
定义: 通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是 “选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了, 则判负(因为他此刻 ...
- ztree2.6给菜单增加title提示信息[转]
自定义数据格式的情况下(isSimpleData: true) 在setting中自定义一个属性如 remark:"remark", callback中调用函数 nodeCreat ...
- 【HDOJ6319】Ascending Rating(单调队列)
题意: 思路: 倒着来是因为这样可以维护每一个当过最大值的数,而正着不行 #include<cstdio> #include<cstring> #include<stri ...
- iOS 用cornerstone 创建分支
第一步:在cornerstone中添加服务器上的代码路径,如下: 第二步:选中服务器路径下的代码,选择“分支”按钮 第三步:开始创建分支 第四步:效果图如下 第五步:选择分支下的路径下载代码并进行修改 ...
- httpclient自动执行http的302重定向
今天debug过程中发现,httpclient会自动执行302的重定向,但是这个的前提是第一个请求是get发出的.我测试发现用post的后的302是系统不会自动redirect的..不知道到底正确不, ...
- 使用图像扫描控件ScanOnWeb实现在线图像扫描
今天上网查资料,看到一篇文章,描述的是一个开发OA软件的公司解决浏览器嵌入式扫描仪编程的文章,文章描述了改OA厂商的工程师如何辛苦的克服了各种技术难题,最终实现了在线图像扫描处理,然后又在无数个不眠的 ...
- 电脑控制手机的另一选择——android vnc server
近来发现的Android上的原生VNC Server,就是说只要手机上安装并运行这个软件,即可实现电脑上查看并控制手机了. 首先是手机端. 1)下载androidvncserver: http://c ...