CF808G Anthem of Berland

Link

大概知道两种 DP 方法。(nlogn 做法太神了)

方法一:

fi 表示 ts[1i] 最多出现次数。当最后一位不会被匹配时,答案为 fi1,否则设答案为 gi。考虑下一次出现的位置,要么在 im+1 之前,要么是满足 [im+1j]=[2imj+1,i] 的位置,直接跳 next 即可。
fi=max{fi1,gi}
gi=max{fim,gj+1}

复杂度 O(|s||t|)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
	x=0;int w=0;char c=GetC();
	for(;!isdigit(c);w|=c=='-',c=GetC());
	for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
	if(w) x=-x;
	return in;
}
const int N=1e5+5,inf=1e9;
char s[N],t[N];
int nxt[N];
int f[N],g[N];
int n,m;
bool check(int i,int j=1){
	for(int x=0;x<m;++x){
		if(s[i+x]!=t[j+x]&&s[i+x]!='?') return false;
	}
	return true;
}
int main(){
	scanf("%s%s",s+1,t+1);
	n=strlen(s+1),m=strlen(t+1);
	int j=0;
	for(int i=2;i<=m;++i){
		while(j&&t[j+1]!=t[i]) j=nxt[j];
		if(t[j+1]==t[i]) ++j;
		nxt[i]=j;
	}
	for(int i=m;i<=n;++i){
		g[i]=-inf;
		if(check(i-m+1)){
			g[i]=f[i-m]+1;
			for(int j=nxt[m];j;j=nxt[j]){
				g[i]=max(g[i],g[i-(m-j)]+1);
			}
		}
		f[i]=max(f[i-1],g[i]);
	}
	printf("%d\n",f[n]);
	return 0;
}

方法二:

dpi,j 表示当主串指针为 i,模式串指针为 j 时的最大出现次数。

对于 ? 枚举填什么。

转移时用 KMP 自动机 实现即可。复杂度 O(|s||t||Σ|)

posted @   pref_ctrl27  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示