Living-Dream 系列笔记 第76期

Posted on 2024-08-07 14:35  _XOFqwq  阅读(5)  评论(0编辑  收藏  举报

UVA1328

简单题。

我们有结论:对于一个周期串 \(S\)子串 \(T\),它的最小循环节即为 \(T-nxt_{\left| T \right|}\)。(具体请查阅往期笔记)

于是,我们枚举所有前缀,检验上式是否能被当前前缀的长度整除并且不止一个循环节即可。

code
#include<bits/stdc++.h>
using namespace std;

const int N=1e7+5;
int nxt[N];

void getnxt(string s){
	int i=0,j=-1;
	nxt[0]=-1;
	for(;i<s.size();){
		if(j==-1||s[i]==s[j])
			i++,j++,nxt[i]=j;
		else
			j=nxt[j];
	}
}

int main(){
	ios::sync_with_stdio(0); 
	//cin>>t;
	int n,p=0; string s;
	while(cin>>n&&n){
		cin>>s;
		getnxt(s);
		cout<<"Test case #"<<(++p)<<'\n';
		for(int i=2;i<=n;i++)
			if(i%(i-nxt[i])==0&&i/(i-nxt[i])>1)
				cout<<i<<' '<<i/(i-nxt[i])<<'\n';
		cout<<'\n';
	}
	return 0;
}

P4591

dp 策略请查阅往期笔记。

我们以前做时,使用的 hash 检验是否匹配,而现在仅需在 kmp 中每当匹配成功就转移即可(kmp + dp 一般在 kmp 中转移)。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int K=1e2+5,A=11,S=1e4+5,MOD=1e9+7;
int n,k,ans;
int dp[K][S],a[K];
string s,t[K][A];
int nxt[S];

void getnxt(string t){
	int i=0,j=-1;
	nxt[0]=-1;
	for(;i<t.size();){
		if(j==-1||t[i]==t[j])
			i++,j++,nxt[i]=j;
		else
			j=nxt[j];
	}
}
void kmp(string s,string t,int cur){
	getnxt(t);
	int i=0,j=0;
	for(;i<s.size();){
		if(j==t.size()-1&&s[i]==t[j]){
			if(i>=t.size())
				dp[cur][i]=(dp[cur][i]+dp[cur-1][i-t.size()])%MOD;
			j=nxt[j];
		}
		if(j==-1||s[i]==t[j])
			i++,j++;
		else
			j=nxt[j];
	}
	//return 0;
}

signed main(){
	cin>>k>>s,n=s.size(),s="#"+s;
	for(int i=1;i<=k;i++){
		cin>>a[i];
		for(int j=1;j<=a[i];j++)
			cin>>t[i][j];
	}
	for(int i=0;i<n;i++) dp[0][i]=1;
	for(int i=1;i<=k;i++){
		for(int u=1;u<=a[i];u++){
			kmp(s,t[i][u],i);
		}
	}
	for(int i=1;i<=n;i++) ans=(ans+dp[k][i])%MOD;
	cout<<ans;
	return 0;
}

P1470

我们发现实际上我们不关心选到集合 \(O\) 中的第几个元素了,我们仅仅关心当前前缀是哪个。

于是考虑这样定义状态:令 \(dp_i\) 表示以 \(i\) 结尾的前缀能 / 不能由 \(O\) 中元素拼接而成。

初始:\(dp_0=1\)

答案:最大的满足 \(i \in [1,n]\)\(dp_i=1\)\(i\)

显然,一个 \(O\) 中元素能拼接成当前前缀,必要条件是当前元素为 \(s\) 的子串。

于是对于每个 \(O\) 中元素将其与 \(s\) 进行 kmp 匹配,记录匹配成功的位置 \(i\) 所对应的元素下标 \(j\)。遍历前缀时,从去除当前前缀的末尾对应的元素的前面部分转移即可。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=2e6+5;
const int MOD=1e9+7;
int n,now,tot,ans;
bool dp[N];
int nxt[N];
string s,p[N];
vector<int> a[N];

void getnxt(string t){
	int i=0,j=-1;
	nxt[0]=-1;
	for(;i<t.size();){
		if(j==-1||t[i]==t[j])
			i++,j++,nxt[i]=j;
		else
			j=nxt[j];
	}
}
void kmp(string s,string t){
	getnxt(t);
	int i=0,j=0;
	for(;i<s.size();){
		if(j==t.size()-1&&s[i]==t[j]){
			a[i].push_back(now);
			j=nxt[j];
		}
		if(j==-1||s[i]==t[j])
			i++,j++;
		else
			j=nxt[j];
	}
}

signed main(){
	while(1){
		cin>>p[++tot];
		if(p[tot]==".") { tot--; break; }
	}
	string t;
	while(cin>>t) s+=t;
	n=s.size(),s="#"+s; 
	dp[0]=1;
	for(int i=1;i<=tot;i++) now=i,kmp(s,p[i]);
	for(int i=1;i<=n;i++)
		for(int j:a[i])
				dp[i]|=dp[i-p[j].size()];
	for(int i=n;i>=0;i--)
		if(dp[i]) cout<<i,exit(0); 
	return 0;
}

HDU 1238

枚举第一个串的每个子串,分别用其正序 / 逆序对其他串跑 kmp,若全都成功则取最长即可。

code
#include<bits/stdc++.h>
using namespace std;

const int N=1e2+5;
int tt,n;
string a[N];
int nxt[N];

void getnxt(string t){
	int i=0,j=-1;
	nxt[0]=-1;
	for(;i<t.size();){
		if(j==-1||t[i]==t[j])
			i++,j++,nxt[i]=j;
		else
			j=nxt[j];
	}
}
bool kmp(string s,string t){
	getnxt(t);
	int i=0,j=0;
	for(;i<s.size();){
		if(j==t.size()-1&&s[i]==t[j])
			return 1;
		if(j==-1||s[i]==t[j])
			i++,j++;
		else
			j=nxt[j];
	}
    return 0;
}

int main(){
	ios::sync_with_stdio(0);
	cin>>tt;
	while(tt--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		int ans=0;
		for(int i=0;i<a[1].size();i++){
			for(int j=i;j<a[1].size();j++){
				string now=a[1].substr(i,j-i+1);
				//cout<<now<<'\n';
				//string now="";
				string tmp=now;
				reverse(now.begin(),now.end());
				string rnow=now;
				now=tmp;
                //cout<<now<<' '<<rnow<<'\n';
				bool f=1;
				for(int k=2;k<=n;k++){
                    //cout<<a[k]<<'\n';
					bool cur1=kmp(a[k],now);
					bool cur2=kmp(a[k],rnow);
					if(cur1==0&&cur2==0){ f=0; break; }
				}
				if(f) ans=max(ans,(int)now.size());
			}
		}
		cout<<ans<<'\n';
	}
	return 0;
}