ICode9

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

洛谷 P4248 [AHOI2013]差异 & P3181 [HAOI2016]找相同字符

2022-01-21 15:00:43  阅读:193  来源: 互联网

标签:tmp cnt le P3181 int AHOI2013 st -- HAOI2016


链接

P4248 P3181


把这两道题放在一起是要讨论这样一个问题

对于一个已知 \(ht\) 的 \(S\),\(O(n)\) 求 \(\sum\limits_{1\le i<j\le n} lcp(i,j)\)

首先我们可以把上式写成 \(\sum\limits_{1\le i\le j}\sum\limits_{1\le j<i}lcp(i,j)\),也就是对于排序后的后缀的一个位置,我们只考虑排名在它之前的后缀与它的lcp。那么我们依次地考虑每个后缀,发现我们实际需要做的是维护一个单调升序列,于是我们只需要用单调栈维护一下 \(ht\) 值和位置就好了。

int sta[N],pos[N],sum[N],now,ans;
inline int solve(){//\sum_{1\le i<j\le n}lcp(i,j) 
	pos[0]=1,ans=0,now=0;
	for(int i=2;i<=n;i++){
		while(now&&ht[i]<=sta[now])now--;
		sta[++now]=ht[i],pos[now]=i,
		sum[now]=sum[now-1]+ht[i]*(pos[now]-pos[now-1]),
		ans+=sum[now];
	}
	return ans;
}

好了回到这两道题。


分析

P4248 [AHOI2013]差异

我们把题目的式子稍微化化,就是
\((n-1)\times\frac{n\times (n+1)}2-2\sum\limits_{1\le i<j\le n} lcp(i,j)\)
直接上。

P3181 [HAOI2016]找相同字符

我们发现发现这题要求的仍然是上面类似的东西,只是子串的来源被分到了两个字符串,这种情况,我们经常用一个特殊字符将两式连接起来一起处理。这样做了后我们发现会算多一部分,这是从某一个串选了两个子串的答案,所以我们只用把两个子串分别处理的结果减掉就好了。

代码

P4248 [AHOI2013]差异
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in read()
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-'0';c=getchar();}
	return p*f;
}
const int N=5e5+5;
int n,m,rk[N<<1],sa[N],ht[N];
struct llmmkk{
	int fi,se,ref;
}st[N<<1],tmp[N<<1];
int cnt[N];
inline void jsort(){
	for(int i=0;i<=n;i++)cnt[i]=0;
	for(int i=1;i<=n;i++)cnt[st[i].se]++;
	for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
	for(int i=n;i>0;i--)tmp[cnt[st[i].se]]=st[i],cnt[st[i].se]--;	
	for(int i=0;i<=n;i++)cnt[i]=0;
	for(int i=1;i<=n;i++)cnt[tmp[i].fi]++;
	for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
	for(int i=n;i>0;i--)st[cnt[tmp[i].fi]]=tmp[i],cnt[tmp[i].fi]--;
}
int ston[257];
inline void SA(string S){
	n=S.length();
	for(int i=0;i<n;i++)ston[signed(S[i])]+=(!ston[signed(S[i])]);
	for(int i=1;i<=256;i++)ston[i]+=ston[i-1];	
	for(int i=1;i<=n;i++)rk[i]=ston[signed(S[i-1])];
	for(int k=1,t;k<=(n<<1);k<<=1){
		for(int i=1;i<=n;i++)
			st[i].fi=rk[i],st[i].se=rk[i+k],st[i].ref=i;	
		jsort();t=0;
		for(int i=1;i<=n;i++){
			if((st[i].fi^st[i-1].fi)||(st[i].se^st[i-1].se))t++;
			rk[st[i].ref]=t;			
		}if(t==n)break;
	}
	for(int i=1;i<=n;i++)sa[rk[i]]=i;
	for(int i=1;i<=n;i++){
		ht[rk[i]]=max(ht[rk[i-1]]-1,0ll);
		while(S[sa[rk[i]-1]+ht[rk[i]]-1]==S[i+ht[rk[i]]-1])
			ht[rk[i]]++;
	}
}
string S;
int sta[N],pos[N],sum[N],now,ans;
inline int solve(){
	pos[0]=1,ans=0,now=0;
	for(int i=2;i<=n;i++){
		while(now&&ht[i]<=sta[now])now--;
		sta[++now]=ht[i],pos[now]=i,
		sum[now]=sum[now-1]+ht[i]*(pos[now]-pos[now-1]),
		ans+=sum[now];
	}
	return ans;
}
signed main(){
	cin>>S;SA(S);
	ans=(n+1)*n/2*(n-1)-2*solve();
	cout<<ans;
	return 0;
}
P3181 [HAOI2016]找相同字符
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in read()
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-'0';c=getchar();}
	return p*f;
}
const int N=4e5+5;
int n,rk[N<<1],sa[N],ht[N];
struct llmmkk{
	int fi,se,ref;
}st[N<<1],tmp[N<<1];
int cnt[N];
inline void jsort(){
	for(int i=0;i<=n;i++)cnt[i]=0;
	for(int i=1;i<=n;i++)cnt[st[i].se]++;
	for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
	for(int i=n;i>0;i--)tmp[cnt[st[i].se]]=st[i],cnt[st[i].se]--;	
	for(int i=0;i<=n;i++)cnt[i]=0;
	for(int i=1;i<=n;i++)cnt[tmp[i].fi]++;
	for(int i=1;i<=n;i++)cnt[i]+=cnt[i-1];
	for(int i=n;i>0;i--)st[cnt[tmp[i].fi]]=tmp[i],cnt[tmp[i].fi]--;
}
int ston[257];
inline void SA(string S){
	n=S.length();memset(ston,0,sizeof(ston));
	for(int i=0;i<n;i++)ston[signed(S[i])]+=(!ston[signed(S[i])]);
	for(int i=1;i<=256;i++)ston[i]+=ston[i-1];	
	for(int i=1;i<=n;i++)rk[i]=ston[signed(S[i-1])];
	for(int k=1,t;k<=(n<<1);k<<=1){
		for(int i=1;i<=n;i++)
			st[i].fi=rk[i],st[i].se=rk[i+k],st[i].ref=i;	
		jsort();t=0;
		for(int i=1;i<=n;i++){
			if((st[i].fi^st[i-1].fi)||(st[i].se^st[i-1].se))t++;
			rk[st[i].ref]=t;			
		}if(t==n)break;
	}
	for(int i=1;i<=n;i++)sa[rk[i]]=i;
	for(int i=1;i<=n;i++){
		ht[rk[i]]=max(ht[rk[i-1]]-1,0ll);
		while(S[sa[rk[i]-1]+ht[rk[i]]-1]==S[i+ht[rk[i]]-1])
			ht[rk[i]]++;
	}
}
string S,T;
int sta[N],pos[N],sum[N],now,ans;
inline int solve(){//\sum_{1\le i<j\le n}lcp(i,j) 
	pos[0]=1,ans=0,now=0;
	for(int i=2;i<=n;i++){
		while(now&&ht[i]<=sta[now])now--;
		sta[++now]=ht[i],pos[now]=i,
		sum[now]=sum[now-1]+ht[i]*(pos[now]-pos[now-1]),
		ans+=sum[now];
	}
	return ans;
}
int tans=0;
signed main(){
	cin>>S>>T;
	SA(S),tans-=solve();
	SA(T),tans-=solve();
	SA(S+'#'+T),tans+=solve();
	cout<<tans;	
	return 0;
}

标签:tmp,cnt,le,P3181,int,AHOI2013,st,--,HAOI2016
来源: https://www.cnblogs.com/llmmkk/p/15830255.html

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

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

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

ICode9版权所有