【bzoj 3670】 [Noi2014]动物园 KMP变式

本文介绍了一种用于字符串匹配的算法,该算法可以计算出在给定限制条件下,字符串前缀与后缀相匹配但不重复的子串数量。通过记录不同长度下匹配成功的状态,实现了对满足特定条件的字符串匹配方案进行计数。

num数组让记录前缀后缀相同且不重复的数的个数,因为有限制条件,前后不能重复,所以匹配的时候如果有重复的也算是匹配失败。

然后是记录方案,考虑在没有约束条件时,记录方案时每次可以从上次失配的地方转移,有约束条件是同理。



#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int n, m;
char a1[1000010];
int f[1000010], num[1000010];
inline int mul(int a, int b){
	int ans = 0;
	for(;b;b>>=1,a=(a*2)%mod) if(b&1) ans = (ans+a)%mod;
	return ans;
}
int main(){
	scanf("%d", &n);
	while(n --){
		scanf("%s", a1+1);
		m = strlen(a1+1);
		for(int i = 1; i <= m; i ++) f[i]=0;
		int p = 0, ans = 1;
		num[1] = 1;
		for(int i = 2; i <= m; i ++){
			while(p && a1[p+1]!=a1[i]) p = f[p];
			if(a1[p+1] == a1[i]) p ++;
			f[i] = p;
			num[i] = num[p]+1;
		}
		p = 0;
		for(int i = 2; i <= m; i ++){
			while(p && (a1[p+1]!=a1[i] || i<2*p+2)) p = f[p];
			if(a1[p+1] == a1[i]) p ++;
			ans = mul(ans, num[p]+1);
		}
		printf("%d\n", ans);
	}
	return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值