CF 494B Obsessive String

https://vjudge.net/problem/CodeForces-494B

题目

给字符串s和t,你可以选择一些字符串s的子串,问有多少种方法满足以下条件

  • 这些字串不重叠
  • 这些字串中都包含t

1 ≤ |s|, |t| ≤ 105

题解

设dp[i]为以i开头有多少种方法可以选择

如果s[i]不是t的开头,要保证包含t又以i开头,那么只能在dp[i+1]的选择方法前面加上一格,dp[i]=dp[i+1]

如果s[i]是t的开头,那么就可以只选择t、选择t后再选择后面的、选择t多一格再选择后面的,选择t多2格再选择后面的……

dp[i]=1+dp[i+|t|]+2*dp[i+|t|+1]+...+?*dp[|s|]

答案是$sum dp[i]$

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
using namespace std;
typedef long long ll;
#define MO 1000000007
char s[100007], t[100007];
int ls, lt;
int dp[100007], ss[100007], s2[100007];
int f[100007];
bool g[100007];
inline void getf(char *s) {
	int t=f[0]=-1;
	int l=strlen(s);
	REP(i,0,l) {
		while(t>=0 && s[i]!=s[t]) t=f[t];
		t++;
		f[i+1]=(s[i+1]!=s[t]?t:f[t]);
	}
}
inline void sear() {
	int j=0;
	REP(i,0,ls) {
		while(~j && s[i]!=t[j]) j=f[j];
		j++;
		if(j==lt) {
			g[i-lt+1]=1;
		}
	}
}
int main() {
	scanf("%s%s", s, t);
	ls=strlen(s), lt=strlen(t);
	getf(t);
	memset(g,0,sizeof g);
	sear();
	dp[ls]=0;
	memset(ss,0,sizeof ss);
	ss[ls]=0; s2[ls]=0;
	PERE(i,ls-1,0) {
		if(g[i]) {
			dp[i]=(ls-i-lt+1)%MO;
			dp[i]=(dp[i]+s2[i+lt]) % MO;
		} else {
			dp[i]=dp[i+1];
		}
		ss[i]=(ss[i+1]+dp[i]) % MO;
		s2[i]=(s2[i+1]+ss[i]) % MO;
	}
	int ans=0;
	REP(i,0,ls) ans=(ans+dp[i])%MO;
	printf("%d
", ans);
}
原文地址:https://www.cnblogs.com/sahdsg/p/12520716.html