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


链接

P4248 P3181


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

对于一个已知 \(ht\)\(S\),\(O(n)\)\(\sum\limits_{1\le i

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

int sta[N],pos[N],sum[N],now,ans;
inline int solve(){//\sum_{1\le i

好了回到这两道题。


分析

P4248 [AHOI2013]差异

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

P3181 [HAOI2016]找相同字符

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

代码

P4248 [AHOI2013]差异
#include
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>S;SA(S);
	ans=(n+1)*n/2*(n-1)-2*solve();
	cout<
P3181 [HAOI2016]找相同字符
#include
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>S>>T;
	SA(S),tans-=solve();
	SA(T),tans-=solve();
	SA(S+'#'+T),tans+=solve();
	cout<