ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[八省联考2018]制胡窜

2021-04-01 12:35:55  阅读:227  来源: 互联网

标签:八省 val int Section rval lval len 制胡窜 联考


XVIII.[八省联考2018]制胡窜

首先,本题parent tree上树上倍增+线段树合并找出每个点的 \(\text{endpos}\) 集合应该是没得说的。

于是我们现在考虑知道了 \(\text{enspos}\) 集合以及询问串长度 \(len\) 怎么求出答案。

首先,一个正常人稍微想想,都应该得出正难则反的推论,因为无论怎么说不合法的划分明显要来得比较工整。

于是问题转化为割两刀,能否切断所有串。我们设最左端串的右端点为 \(L\),最右端串的右端点为 \(R\)。同时,设所有串的端点集合为 \(p_1,p_2,\dots,p_m\)。明显有 \(p_1=L,p_m=R\)。

  1. 若出现三个及以上无交串则无不合法划分。这是显然的,因为一次只能割断一个无交串。
  2. 若最左端的串与最右端的串有交,则两两串皆有交。考虑此种情形。

首先,此时,所有串的交集非空,等于最左串与最右串的交集,这是显然的。

则,若有至少一刀砍到了此交集上,则所有串就都被砍到了。

交集长度为 \(L-R+len\)。从中砍两刀,总方案数为 \(\dbinom{L-R+len-1}{2}\)。从中只砍一刀,方案数为 \((L-R+len-1)\times(n-len)\)。

若一刀都没有砍到此交集上,则显然有一刀砍到了 \(p_{1\sim i}\) 的交集上,另一刀砍到了 \(p_{i+1\sim m}\) 的交集上,其中 \(i\in[1,m)\)。

则,此部分答案为 \(\sum\limits_{i=1}^{m-1}[p_i-len+1,p_{i+1}-len+1)\times[R-len+1,p_{i+1})\),其中两段东西分别是两刀可以取到的区间。计算区间长度之积,是 \(\sum\limits_{i=1}^{m-1}(p_{i+1}-p_i)\times(p_{i+1}-R+len-1)\)。拆成与 \(p\) 有关的项和无关的项,得到 \(\sum\limits_{i=1}^{m-1}p_{i+1}(p_{i+1}-p_i)-(R-len+1)\sum\limits_{i=1}^{m-1}p_{i+1}-p_i\)。继续展开,最终得到 \(\Big(\sum\limits_{i=1}^{m-1}p_{i+1}(p_{i+1}-p_i)\Big)-(R-len+1)(R-L)\)。最左边那一大坨可以在线段树合并时顺手维护掉,右边一大坨可以 \(O(1)\) 直接计算。

  1. 若最左端串与最右端串无交。

首先,对于与左右两端串皆有交的串来说,其仍然可以与前一种情形一样地计算。准确来说,若设 \(lp\) 表示最左的与 \(R\) 有交的串,\(rp\) 表示最右的与 \(L\) 有交的串,则仍有此部分答案为 \(\Big(\sum\limits_{i=lp}^{rp-1}p_{i+1}(p_{i+1}-p_i)\Big)-(R-len+1)(p_{rp}-p_{lp})\)。

但是,有一个例外。我们可以在 \([p_{rp}-len+1,L]\) 这段区间里砍一刀。这时,找到 \(np\) 是最左的与 \(L\) 无交的串,则此串必与 \(R\) 有交。于是,另一刀就砍在 \(np\) 与 \(R\) 的交集上,这时也能达成目标。

时间复杂度 \(O(n\log n)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read(){
	int x=0;
	char c=getchar();
	while(c>'9'||c<'0')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x;
}
int n=read(),m=read(),cnt=1,anc[200100][20],id[100100],tot;
char s[100100];
struct Suffix_Automaton{int ch[10],fa,len;}t[200100];
int Add(int x,int c){
	int xx=++cnt;t[xx].len=t[x].len+1;
	for(;x&&!t[x].ch[c];x=t[x].fa)t[x].ch[c]=xx;
	if(!x){t[xx].fa=1;return xx;}
	int y=t[x].ch[c];
	if(t[y].len==t[x].len+1){t[xx].fa=y;return xx;}
	int yy=++cnt;t[yy]=t[y],t[yy].len=t[x].len+1;
	t[xx].fa=t[y].fa=yy;
	for(;x&&t[x].ch[c]==y;x=t[x].fa)t[x].ch[c]=yy;
	return xx;
}
int rt[200100];
#define mid ((l+r)>>1)
struct Section{
	int lval,rval;
	ll val;
	Section(){lval=0,rval=n+1,val=0;}
	Section(int P){lval=rval=P,val=0;}
	Section(int L,int R,ll V){lval=L,rval=R,val=V;}
	void print()const{printf("%d %d %lld\n",lval,rval,val);}
	bool empty()const{return !lval&&rval==n+1;}
	friend Section operator+(const Section&l,const Section&r){
		if(l.empty())return r;if(r.empty())return l;
		return Section(l.lval,r.rval,l.val+r.val+1ll*r.lval*(r.lval-l.rval));
	}
};
struct SegTree{int lson,rson,sum;Section val;}seg[4001000];
void modify(int &x,int l,int r,int P){
	if(l>P||r<P)return;
	if(!x)x=++tot;seg[x].sum++;
	if(l!=r)modify(seg[x].lson,l,mid,P),modify(seg[x].rson,mid+1,r,P),seg[x].val=seg[seg[x].lson].val+seg[seg[x].rson].val;
	else seg[x].val=Section(P);
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	int z=++tot;seg[z].sum=seg[x].sum+seg[y].sum;
	seg[z].val=seg[seg[z].lson=merge(seg[x].lson,seg[y].lson)].val+seg[seg[z].rson=merge(seg[x].rson,seg[y].rson)].val;
	return z;
}
int inneraskleft(int x,int l,int r){if(l==r)return l;if(seg[seg[x].lson].sum)return inneraskleft(seg[x].lson,l,mid);return inneraskleft(seg[x].rson,mid+1,r);}
int outeraskleft(int x,int l,int r,int L,int R){
	if(l>R||r<L||!x)return -1;
	if(L<=l&&r<=R){
		if(!seg[x].sum)return -1;
		return inneraskleft(x,l,r);
	}
	int tmp=outeraskleft(seg[x].lson,l,mid,L,R);
	if(tmp!=-1)return tmp;
	return outeraskleft(seg[x].rson,mid+1,r,L,R);
}
int inneraskright(int x,int l,int r){if(l==r)return r;if(seg[seg[x].rson].sum)return inneraskright(seg[x].rson,mid+1,r);return inneraskright(seg[x].lson,l,mid);}
int outeraskright(int x,int l,int r,int L,int R){
	if(l>R||r<L||!x)return -1;
	if(L<=l&&r<=R){
		if(!seg[x].sum)return -1;
		return inneraskright(x,l,r);
	}
	int tmp=outeraskright(seg[x].rson,mid+1,r,L,R);
	if(tmp!=-1)return tmp;
	return outeraskright(seg[x].lson,l,mid,L,R);
}
int querycount(int x,int l,int r,int L,int R){
	if(l>R||r<L||!x)return 0;
	if(L<=l&&r<=R)return seg[x].sum;
	return querycount(seg[x].lson,l,mid,L,R)+querycount(seg[x].rson,mid+1,r,L,R);
}
void iterate(int x,int l,int r){if(!x)return;printf("%d[%d,%d]:%d\n",x,l,r,seg[x].sum);if(l!=r)iterate(seg[x].lson,l,mid),iterate(seg[x].rson,mid+1,r);}
vector<int>v[200100];
void dfs(int x){for(auto y:v[x])anc[y][0]=x,dfs(y),rt[x]=merge(rt[x],rt[y]);}
int doubling(int l,int r){int x=id[r];for(int i=19;i>=0;i--)if(anc[x][i]&&t[anc[x][i]].len>=r-l+1)x=anc[x][i];return x;}
Section queryarea(int x,int l,int r,int L,int R){
	if(l>R||r<L||!x)return Section();
	if(L<=l&&r<=R){return seg[x].val;}
	return queryarea(seg[x].lson,l,mid,L,R)+queryarea(seg[x].rson,mid+1,r,L,R);
}
ll calc(int x,int len){
//	iterate(rt[x],1,n);
	int L=outeraskleft(rt[x],1,n,1,n),R=outeraskright(rt[x],1,n,1,n);
	if(L+len<R-len+1&&querycount(rt[x],1,n,L+len,R-len))return 0;//three non-intersect
	if(L>=R-len+1){//two intersect
		ll A=seg[rt[x]].val.val-1ll*(R-len+1)*(R-L);//cut two useful
		ll B=1ll*(L-R+len-1)*(L-R+len-2)/2+1ll*(L-R+len-1)*(n-len);//cut one useful
		return A+B;
	}
	int lp=outeraskright(rt[x],1,n,L,R-len+1),rp=outeraskright(rt[x],1,n,L,L+len-1),np=outeraskleft(rt[x],1,n,L+len-1,R);
//	printf("%d %d %d\n",lp,rp,np);
	ll ret=0;if(lp<=rp)ret+=queryarea(rt[x],1,n,lp,rp).val-1ll*(R-len+1)*(rp-lp);
	if(np>R-len+1)ret+=1ll*(L-rp+len-1)*(np-R+len-1);
	return ret;
}
int main(){
	scanf("%s",s+1);
	for(int i=1,las=1;i<=n;i++)las=id[i]=Add(las,s[i]-'0');
	for(int i=1;i<=n;i++)modify(rt[id[i]],1,n,i);
	for(int i=2;i<=cnt;i++)v[t[i].fa].push_back(i);
	dfs(1);
	for(int j=1;j<=19;j++)for(int i=1;i<=cnt;i++)anc[i][j]=anc[anc[i][j-1]][j-1];
//	for(int j=0;j<=3;j++){for(int i=1;i<=cnt;i++)printf("%d ",anc[i][j]);puts("");}
//	for(int i=1;i<=cnt;i++)printf("%d ",t[i].len);puts("");
	for(int i=1,l,r;i<=m;i++)l=read(),r=read(),printf("%lld\n",1ll*(n-1)*(n-2)/2-calc(doubling(l,r),r-l+1));
	return 0;
}

标签:八省,val,int,Section,rval,lval,len,制胡窜,联考
来源: https://www.cnblogs.com/Troverld/p/14605747.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有