题目大意

给出一个字符串$S$,长度为$n$(\(n\leq 10^5\)),$S[l:r]$表示$S_l,S_{l+1}...,S_r$这个子串。有$m$(\(m\leq 3\times 10^5\))次询问,每次询问给出$l,r$,问有多少对$(i,j)$($1\leq i<i+1<j\leq n$),使与$S[l:r]$本质相同的子串出现在$S[1:i]$中或$S[i+1:j-1]$中或$S[j:n]$中。

题解

询问相当于是问有多少种方案在$S$中找两个缝隙切两刀,使两刀不重合,且存在一个与$S[l:r]$本质相同的子串没被切。
这个比较难考虑,可以把它转换成 在$n-1$个缝隙中选两个的总方案数-所有与$S[l:r]$本质相同的子串都被切的方案数。
所有与$S[l:r]$本质相同的子串都被切的方案数分以下几种情况考虑:
一、$S$中存在三个与$S[l:r]$本质相同的子串,且其中每两个的交集大小不超过1
会发现此时怎么切两刀都切不全这三个串,方案数为0。
二、$S$中不存在三个与$S[l:r]$本质相同的子串,且其中每两个的交集大小不超过1:假设所有这样的子串的最左的左端点为$ll$,最左的右端点为$lr$,最右的左端点为$rl$,最右的右端点为$rr$,$S[l:r]$长度为$len$,$r_i$表示right集合的第$i$个。
\(\space\space\space\space\) 1.$S$中所有与$S[l:r]$本质相同的子串的交集不为空
\(\space\space\space\space\) \(\space\space\space\space\)(1)靠前的一刀没切到与$S[l:r]\(本质相同的子串:另一刀必须切在所有这样的子串的交集\)[rl,lr]$上。这部分答案=\(ll\times (lr-rl)\)。注意刀只能切在缝隙上,所以是$(rl-lr)\(而不是\)(rl-lr+1)$。
\(\space\space\space\space\) \(\space\space\space\space\)(2)靠前的一刀切到了一些与$S[l:r]$本质相同的子串,但没切在所有与$S[l:r]\(本质相同的子串的交集上:会发现第二刀肯定要切在第一刀没切到的子串的交集上。所以对于两种方案,当它们第一刀切的串相同时,第二刀可行的取值范围相同。两种方案的第一刀都在\)[r_i-len+1,r_{i+1}-len+1)\(时,它们切的串都是\)[1,i]\(这个区间中的,它们第二刀的取值范围都是\)[rl,r_{i+1}]\(。也就是说,这部分答案=\)\sum(r_{i+1}-r_i)\times(r_{i+1}-rl)$
\(\space\space\space\space\) \(\space\space\space\space\)(3)靠前的一刀切到所有与$S[l:r]$本质相同的子串的交集上:其实这部分与(1)合并后就是“存在一刀切在所有与$S[l:r]$本质相同的子串的交集上,但靠前的一刀不是(2)的情况”。两刀都切在交集上的方案数是$C_^2$。对于只有一刀切在交集上的情况,相当于其中一刀不能在$[lr-len+1,lr]\(上,另一刀必须在\)[lr,rl]$上,所以这部分是 \((n-len)\times(lr-rl)\)。也就是说(1)和(3)总共是$C_2+(n-len)\times(lr-rl)$。
\(\space\space\space\space\) 2. $S$中所有与$S[l:r]$本质相同的子串的交集为空:两刀必须都切到与$S[l:r]\(本质相同的子串,且都切不到这些子串的交集,和上一种情况的(2)类似。但是第一刀可能切不到最左的串,\)[rl,r_{i+1}]$也可能是空集。发现当$r_i-len+1<lr$且$r_{i+1}>rl$时,第一刀切在$[r_i,r_{i+1})\(都是合法的。这种情况的答案是\)\sum\limits_{r_{i+1}>rl}
{r_i-len+1<lr}(r_{i+1}-r_i)\times(r_{i+1}-rl)\(。还可能有一段\)[r_i,r_{i+1})$,满足$lr\in[r_i-len+1,r_{i+1}-len+1)\(即\)(lr+len-1)\in[r_i,r_{i+1})\(,这一段中比较靠前的地方\)[r_i-len+1,lr]$可以切,靠后的不可以切。计算这种情况需要求$lr+len-1$左边第一个right集合的元素$r_p$和右边第一个$r_s$。这部分的答案是$(lr-r_p+len-1)\times (r_s-rl)$,需要注意的是,当$r_s\leq rl$时这部分的答案是0。

需要维护right集合和$\sum(r_{i+1}-r_i)\times(r_{i+1}-rl)$,可以拆成$s_1(l,r)=\sum(r_{i+1}-r_i)$和$s_2(l,r)=\sum(r_{i+1}-r_i)\times r_{i+1}$,这样就可以线段树维护区间right集合中最左和最右,合并时$s1(l,r)=s1(l,mid)+s1(mid+1,r)+min(mid+1,r)-max(l,mid)$,\(s2(l,r)=s2(l,mid)+s2(mid+1,r)+(min(mid+1,r)-max(l,mid))\times min(mid+1,r)\)。
求right集合需要线段树合并。据说不离线的话,“可持久化 线段树合并”会MLE。
#####代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#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 view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define LL long long
#define maxn 100007
#define maxnd 200007
#define maxq 300007
#define maxk 6400007
#define ls son[u][0]
#define rs son[u][1]
#define mi (l+r>>1)
#define Ls(u) son[u][0]
#define Rs(u) son[u][1]
#define pb push_back
#define int long long
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int n,ch[maxnd][10],dis[maxnd],rt[maxnd],fa[maxnd],pt[maxn],lst,cnt,rot;
int son[maxk][2],cntnd,m,c[maxn],ord[maxnd],anc[maxnd][20];
char s[maxn];
LL ans[maxq];
struct node{int mx,mn;LL sum[2];}tr[maxk];
struct quest{int l,r,id;};
vector<quest>qt[maxnd];
void gt(node & x,node y){x.mx=y.mx,x.mn=y.mn,x.sum[0]=y.sum[0],x.sum[1]=y.sum[1];return;}
void pu(node & x,node ld,node rd)
{
x.mx=rd.mx,x.mn=ld.mn,x.sum[0]=ld.sum[0]+rd.sum[0]+(LL)(rd.mn-ld.mx),x.sum[1]=ld.sum[1]+rd.sum[1]+(LL)(rd.mn-ld.mx)*rd.mn;
return;
}
int build(int u,int l,int r,int x)
{
if(!u)u=++cntnd;
if(x<=l&&r<=x){tr[u].mx=tr[u].mn=x,tr[u].sum[0]=tr[u].sum[1]=0;return u;}
if(x<=mi)ls=build(ls,l,mi,x);
else rs=build(rs,mi+1,r,x);
if(!ls||!rs)gt(tr[u],tr[ls|rs]);
else pu(tr[u],tr[ls],tr[rs]);return u;
}
int merge(int ua,int ub,int l,int r)
{
if(!ua||!ub)return ua|ub;
Ls(ua)=merge(Ls(ua),Ls(ub),l,mi);
Rs(ua)=merge(Rs(ua),Rs(ub),mi+1,r);
if(!Ls(ua)||!Rs(ua))gt(tr[ua],tr[Ls(ua)|Rs(ua)]);
else pu(tr[ua],tr[Ls(ua)],tr[Rs(ua)]);return ua;
}
void ask(int u,int l,int r,int x,int y,node & k)
{
if(!u||x>y)return;
if(x<=l&&r<=y){if(k.mx==0)gt(k,tr[u]);else pu(k,k,tr[u]);return;}
if(x<=mi&&ls)ask(ls,l,mi,x,y,k);
if(y>mi&&rs)ask(rs,mi+1,r,x,y,k);
return;
}
int pref(int u,int x){node kk;kk.mx=kk.mn=0,ask(u,1,n,1,x,kk);return kk.mx;}
int sufx(int u,int x){node kk;kk.mx=kk.mn=0,ask(u,1,n,x,n,kk);return kk.mn;}
int gx(char c){return c-'0';}
void ext(int i)
{
int p=lst,v=gx(s[i]),np=++cnt;dis[np]=i,lst=pt[i]=np;rt[np]=build(rt[np],1,n,i);
for(;p&&!ch[p][v];p=fa[p])ch[p][v]=np;
if(!p)fa[np]=rot;
else
{
int q=ch[p][v];
if(dis[p]+1==dis[q])fa[np]=q;
else
{
int 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][v]==q;p=fa[p])ch[p][v]=nq;
}
}
}
int tp[maxq];
LL c2(int x){return (LL)x*(x-1)/2ll;}
signed main()
{
rot=lst=cnt=1;
scanf("%d%d%s",&n,&m,s+1);
rep(i,1,n)ext(i);
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;
rep(j,1,cnt)
{
int i=ord[j];
anc[i][0]=fa[i];
rep(k,1,19)anc[i][k]=anc[anc[i][k-1]][k-1];
}
rep(i,1,m)
{
int l=read(),r=read(),nd=pt[r];
dwn(j,19,0)if(dis[anc[nd][j]]>=r-l+1)nd=anc[nd][j];
quest q;q.l=l,q.r=r,q.id=i;qt[nd].pb(q);
}
dwn(j,cnt,1)
{
int i=ord[j],sz=qt[i].size(),rr=tr[rt[i]].mx,lr=tr[rt[i]].mn;
rep(k,0,sz-1)
{
int len=qt[i][k].r-qt[i][k].l+1,rl=rr-len+1,nd3=0;
if(lr+len-1<=n)nd3=sufx(rt[i],lr+len-1);
if(nd3&&nd3<=rl){tp[qt[i][k].id]=3;continue;}
if(lr>rl){tp[qt[i][k].id]=1;ans[qt[i][k].id]=-tr[rt[i]].sum[0]*((LL)rl)+tr[rt[i]].sum[1]+c2(lr-rl)+(LL)(lr-rl)*(n-len);}
else
{
int sec,fst=pref(rt[i],rl);
node kk;kk.mx=kk.mn=0;if(fst)ask(rt[i],1,n,fst,lr+len-1,kk);
if(kk.mx)ans[qt[i][k].id]=-(LL)rl*kk.sum[0]+kk.sum[1];
fst=sec=0;
if(lr+len-1<=n)fst=pref(rt[i],lr+len-1),sec=sufx(rt[i],lr+len-1);
if(sec&&fst&&sec>rl)ans[qt[i][k].id]+=(LL)(lr-fst+len-1)*(sec-rl);
tp[qt[i][k].id]=2;
}
}
rt[fa[i]]=merge(rt[fa[i]],rt[i],1,n);
}
rep(i,1,m){write(c2(n-1)-ans[i]);}
return 0;
}

#####一些感想
写一下调一年,自闭不花一分钱

并不对劲的复健训练-bzoj5253:loj2479:p4384:[2018多省联考]制胡窜的更多相关文章

  1. 并不对劲的复健训练-bzoj5249:loj2472:p4364[2018多省联考]IIIDX

    题目大意 给出\(n,k,d_1,...,d_n\)(\(n\leq 5\times 10^5,1<k\leq 10^9,d\leq 10^9,k\in R\)).有一个满足 对于每个点\(i\ ...

  2. 并不对劲的复健训练-CF1187D

    题目大意 有两个长度为\(n\)的序列\(a_1,...,a_n\),\(b_1,...,b_n\)(\(a,b\leq n\leq 3\times 10^5\) ).一次操作是选取 \([l,r]\ ...

  3. 并不对劲的复健训练-bzoj5250:loj2473:p4365:[九省联考2018]秘密袭击

    题目大意 有一棵\(n\)(\(n\leq 1666\))个点的树,有点权\(d_i\),点权最大值为\(w\)(\(w\leq 1666\)).给出\(k\)(\(k\leq n\)),定义一个选择 ...

  4. 并不对劲的复健训练-bzoj5339:loj2578:p4593:[TJOI2018]教科书般的亵渎

    题目大意 题目链接 题解 先将\(a\)排序. \(k\)看上去等于怪的血量连续段的个数,但是要注意当存在\(a_i+1=a_{i+1}\)时,虽然它们之间的连续段为空,但是还要算上:而当\(a_m= ...

  5. 并不对劲的复健训练-CF1205B Shortest Cycle

    题目大意 有\(n\)(\(n\leq 10^5\))个数\(a_1,...,a_n\)(\(a\leq 10^{18}\)).有一个图用这个方法生成:若\(a_i\)按位与\(a_j\)不为0,则在 ...

  6. 并不对劲的复健训练-p5212 SubString

    题目大意 有一个串\(s\),一开始只知道它的一个前缀.有\(q\)(\(q\leq 10^4\))个操作,操作有两种:1.给一个字符串,表示\(s\)(\(s\)总长\(\leq 6\times 1 ...

  7. 并不对劲的复健训练-bzoj5301:loj2534:p4462 [CQOI2018]异或序列

    题目大意 给出一个序列\(a_1,...,a_n\)(\(a,n\leq 10^5\)),一个数\(k\)(\(k\leq 10^5\)),\(m\)(\(m\leq10^5\))次询问,每次询问给\ ...

  8. 并不对劲的复健训练-p3674

    题目大意 给出序列$ a_1,...,a_n $ ( $ n\leq10^5,a\leq 10^5 $ ),有\(m\) ( \(m\leq 10^5\))个以下三类询问: (1)给出\(l,r,k\ ...

  9. bzoj5253 [2018多省省队联测]制胡窜

    后缀自动机挺好毒瘤的题. 我们考虑哪些切点是不合法的.肯定是所有的匹配串都被切了. 我们考虑第一个切口的位置. 当第一个切口在第一个出现位置前时,第二个切口必须切掉所有的串. 当第一个切口在$l_{i ...

随机推荐

  1. gradle添加阿里云maven库

    用gradle构建spring项目,才发现gradle要添加阿里云maven库和maven不太一样 链接:https://www.cnblogs.com/SiriYang/p/10638365.htm ...

  2. 字符串暴力枚举子序列求LCS

    题意: 求n个串里的LCS,长度相同时按照字典序排序 solution: 断环为链,二进制枚举子序列,压入vector,按照字典序排序 把出现次数为n的,压入第二个vector 输出最长的第二个vec ...

  3. python 格式化输出用户名/密码

    格式化输出用户名/密码 内容来自网络 def get_account(num): accounts = [] for index in range(1, num+1): accounts.append ...

  4. zabbix自定义监控,自定义图表。

    zabbix server:hostname=Zabbix server ip:192.168.100.7 zabbix agent: hostname=host3 ip:192.168.100.3 ...

  5. css3_1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. CSS 优先级法则

    样式的优先级 多重样式(Multiple Styles):如果外部样式.内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况. 一般情况下,优先级如下: (外部样式)External styl ...

  7. LC 970. Powerful Integers

    Given two non-negative integers x and y, an integer is powerful if it is equal to x^i + y^j for some ...

  8. Kafka管理与监控——彻底删除topic

    一.配置 server.properties 设置 delete.topic.enable=true 如果没有设置 delete.topic.enable=true,则调用kafka 的delete命 ...

  9. laravel如何打印orm封装的sql语句

    $query = CdbForumSellthreadSearch::where($params)->orderBy("$orderby", "$ascDesc&q ...

  10. SpringBoot: 2.SpringBoot整合servlet(转)

    整合方式1:通过注解扫描完成 Servlet 组件的注册 1.编写servlet package com.bjsxt.servlet; import javax.servlet.ServletExce ...