交差との連結(2800 / zアルゴリズム/ツリー配列/ダブルポインター)

タイトル:http : //codeforces.com/contest/1313/problem/E
リファレンス:http : //codeforces.com/blog/entry/74146
タイトル:指定された文字列a、b、s。次のような部分文字列の組み合わせの数を見つけます a [ l 1 , r 1 ] + b [ l 2 , r 2 ] = = s a [l1、r1] + b [l2、r2] == s 、リクエスト [ l 1 , r 1 ] , [ l 2 , r 2 ] [l1、r1]、[l2、r2] 交差は空ではありません。
解決策:zアルゴリズムを使用して、sのaの最長プレフィックスを見つけます l c p lcp 、sのbの最長サフィックス l c s lcs 文字列を左から右に列挙し、取る l 1 l_1 、次に対応する r 2 r_2 値は l 1 < = r 2 < = l 1 + m 2 l_1 <= r_2 <= l_1 + m-2 、現在の間隔を満たすすべてのものを入れます r 2 r_2 対応する左端のエンドポイント r 2 l c s r 2 r_2-lcs_ {r_2} それらをツリーのような配列に入れて、それぞれ数と合計を数えます c n t s u m CNT、I
その後、現在 l 1 l_1 左端のケースの数は l c s c n t s u m lcs * cnt-sum s u m パーツは使用できないため、差し引く必要があります。これは大まかに抽象的な説明にすぎません。コードの実装と理論上の説明には相違があります。詳細については、コードを参照してください。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500010;
#define ll long long

int n,m;
char a[maxn],b[maxn];
char s[maxn*2],c[maxn*3];
int z[maxn*3];
int lcp[maxn];//lcp[i]表示a[i]开始,能匹配s的最长前缀 
int lcs[maxn];//lcs[i]表示b[i]开始,能匹配s的最长后缀 
//z算法,求解给定字符串每个位置能匹配自身的最长前缀 
void z_init(int len) {
	int l = 1,r = 1;
	z[1] = len;
	for(int i = 2;i <= len;i++) {
		if(i > r) {
			l = i;r = i;
			while(r<=len && c[r-i+1]==c[r]) r++;
			z[i] = r-l;r--;
		}else {
			int k = i-l+1;
			if(z[k]<r-i+1) z[i] = z[k];
			else {
				l = i;
				while(r<=len && c[r-i+1]==c[r]) r++;
				z[i] = r-l;r--;
			}
		}
	}
}
void init() {
	//求lcp 
	for(int i = 1;i <= m;i++) c[i] = s[i];
	c[m+1] = '#';
	for(int i = 1;i <= n;i++) c[m+1+i] = a[i];
	c[n+m+2] = '\0';
	z_init(n+m+1);
	for(int i = 1;i <= n;i++) lcp[i] = z[m+1+i];
	//求lcs
	for(int i = 1;i <= m;i++) c[i] = s[m+1-i];
	c[m+1] = '#';
	for(int i = 1;i <= n;i++) c[m+1+i] = b[n+1-i];
	c[n+m+2] = '\0';
	z_init(n+m+1);
	for(int i = 1;i <= n;i++) lcs[i] = z[m+1+n+1-i];
}
//Fenwick Tree
ll cnt[maxn*2],sum[maxn*2];
int lowbit(int x) {
	return x&(-x); 
} 
void add(int v) {
	int x = v;
	while(x <= n) sum[x]+=v,cnt[x]++,x+=lowbit(x);
}
void sub(int v) {
	int x = v;
	while(x <= n) sum[x]-=v,cnt[x]--,x+=lowbit(x);
}
ll get_sum(int x) {
	ll res = 0;
	while(x) res+=sum[x],x-=lowbit(x);
	return res;
}
ll get_cnt(int x) {
	ll res = 0;
	while(x) res+=cnt[x],x-=lowbit(x);
	return res;
} 
int main() {
	scanf("%d%d",&n,&m);
	scanf("%s%s%s",a+1,b+1,s+1);
	init();//puts("VE");
	ll ans = 0;
	/*
	*l1 <= r2 <= l1+m-2 as |r2-l1| <= m-1
	*initial l1 = 1
	*/
	for(int i = 1;i <= min(n,m-1);i++) add(max(1,m-lcs[i]));//puts("S");
	for(int i = 1,r;i <= n;i++) {
		r = min(m-1,lcp[i]);
		ans += 1LL*(r+1)*get_cnt(r)-get_sum(r);
		sub(max(1,m-lcs[i]));//delete case of "i as r2"
		if(i+m-1 <= n) add(max(1,m-lcs[i+m-1]));//add case of "i+m-1 as r2" 
	}
	printf("%I64d\n",ans); 
} 
公開された152元の記事 ウォンの賞賛2 ビュー6457

おすすめ

転載: blog.csdn.net/weixin_43918473/article/details/104655510