P9576 题解

赛时没仔细想,赛后才发现并不难。

\(l,r\)\(l',r'\) 是否相交分开讨论。

假若不相交,那么 \(l',r' < l\) 或者 \(l',r' > r\) 并且 \([l',r']\) 内的字符一定与字符串 \(t\) 匹配上了,考虑做一遍字符串匹配再利用乘法原理计算 \(l,r\) 的取值数量即可。

假若相交,那么就是区间 \([l',l]\) 与区间 \([r,r']\) 拼接起来构成了字符串 \(t\),不难想到这一定是一段 \(t\) 的前缀后缀拼接起来,所以自然可以考虑对于 \(s\) 字符串中每个位置求出其与 \(t\) 匹配的最大前缀后缀,然后实际上问题就变成了一个二维数点,考虑离线扫描一遍,线段树维护贡献即可。

考虑使用字符串哈希加上二分快速的求出相匹配的最大前缀后缀,加上线段树,总复杂度 \(O(n \log n)\),其中 \(n\) 是字符串长度。

#include<bits/stdc++.h>
#define int unsigned long long
//#define lowbit(x) (x&-(x))
using namespace std;
const int maxn = 1e6+114;
const int base = 1331;
int _pow[maxn];
int pre[maxn];//s的前缀哈希值
int Pre[maxn];//t的前缀哈希值
int L[maxn],R[maxn];//从s第i位开始匹配往左往右最多匹配多少位
char s[maxn],t[maxn];//字符串 s,t 下标从 1 开始
int ans;
int lens,lent;
bool check1(int pos,int len){
	if(pos-len+1<1) return false;
	int lt=pos-len+1,rt=pos;
	int Lt=lent-len+1,Rt=lent;
	return (pre[rt]-pre[lt-1])*_pow[Lt]==(Pre[Rt]-Pre[Lt-1])*_pow[lt];
}
bool check2(int pos,int len){
	if(pos+len-1>lens) return false;
	int lt=pos,rt=pos+len-1;
	int Lt=1,Rt=len;
	return (pre[rt]-pre[lt-1])*_pow[Lt]==(Pre[Rt]-Pre[Lt-1])*_pow[lt];
}
void init(){//预处理好以上所有数组 
	lens=strlen(s)-1;
	lent=strlen(t)-1;
	_pow[0]=1;
	for(int i=1;i<maxn;i++) _pow[i]=_pow[i-1]*base;
	for(int i=1;i<=lens;i++) pre[i]=pre[i-1]+(int)(s[i])*_pow[i];
	for(int i=1;i<=lent;i++) Pre[i]=Pre[i-1]+(int)(t[i])*_pow[i];
	for(int i=1;i<=lens;i++){
		int l=0,r=lent+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(check1(i,mid)==true) l=mid;
			else r=mid;
		}
		L[i]=l;
		l=0,r=lent+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(check2(i,mid)==true) l=mid;
			else r=mid;
		}
		R[i]=l;
	}
	for(int i=1;i<=lens;i++){
		if(R[i]==lent){//匹配区域与删除区域不交 
			if(i>=1) ans+=(i-1)*i/2;
			if(i<=lens-lent) ans+=(lens-(i+lent-1))*(lens-(i+lent-1)+1)/2;
		}
	}
} 
int tr[maxn<<2],tag[maxn<<2];
#define ls(cur)(cur<<1)
#define rs(cur)(cur<<1|1)
void pushup(int cur){
	tr[cur]=tr[ls(cur)]+tr[rs(cur)];
}
void pushdown(int cur,int lt,int rt){
	int mid=(lt+rt)>>1;
	tr[ls(cur)]+=tag[cur]*(mid-lt+1);
	tag[ls(cur)]+=tag[cur];
	tr[rs(cur)]+=tag[cur]*(rt-mid);
	tag[rs(cur)]+=tag[cur];
	tag[cur]=0;
}
void add(int cur,int lt,int rt,int l,int r,int v){
    if(lt>rt) return ;
	if(l<=lt&&rt<=r){
		tr[cur]+=v*(rt-lt+1),tag[cur]+=v;
		return ;
	}
	if(rt<l||lt>r) return ;
	pushdown(cur,lt,rt);
	int mid=(lt+rt)>>1;
	add(ls(cur),lt,mid,l,r,v);
	add(rs(cur),mid+1,rt,l,r,v);
	pushup(cur);
}
int query(int cur,int lt,int rt,int l,int r){
    if(lt>rt) return 0;
	if(l<=lt&&rt<=r) return tr[cur];
	if(rt<l||lt>r) return 0;
	pushdown(cur,lt,rt);
	int mid=(lt+rt)>>1;
	return query(ls(cur),lt,mid,l,r)+query(rs(cur),mid+1,rt,l,r);
}
signed main(){
	scanf("%s%s",s+1,t+1);
    s[0]=t[0]='a';
	init();
	for(int i=lens;i>=1;i--){
		if(i+lent<=lens){
			add(1,1,lent,1,min(L[i+lent],lent-1),1);
		}
		ans+=query(1,1,lent,max((int)(1),lent-R[i]),lent-1);
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2024-01-31 00:00  ChiFAN鸭  阅读(2)  评论(0编辑  收藏  举报