首页 > 其他分享 >Living-Dream 系列笔记 第76期

Living-Dream 系列笔记 第76期

时间:2024-08-07 14:39:26浏览次数:6  
标签:Living string nxt int getnxt 76 Dream dp 前缀

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=1i

显然,一个 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;
}

标签:Living,string,nxt,int,getnxt,76,Dream,dp,前缀
From: https://www.cnblogs.com/XOF-0-0/p/18346998

相关文章

  • Dreamforce '24重磅来袭!年度盛会将有何惊喜?
     作为Salesforce的旗舰会议,Dreamforce的历史已有20余年之久,是生态系统中的年度亮点。现如今,Dreamforce已经适应了线上受众的需求,通过Salesforce+提供直播和点播的参与方式。 近期,Salesforce宣布Dreamforce'24将于9月17日-19日举行,一年一度的科技盛会又要开始 Dreamforce......
  • CodeForces - 765F
    不妨套用P9058的套路,记点对\((i,j),a_i\gea_j\)被支配当且仅当存在\(i<k<j\),满足\(a_i\gea_k\gea_j\),同样,猜测对于\(i\),不被支配的点对\((k,i)\)只满足\(k<i\)最大且\(a_k>a_i\)。证明不妨使用反证法,记\(pre\),满足\(pre<j<i\)且\(a_{pre},a_j>a_i\),假设\((p......
  • Dreamweaver (DW)2021 下载 安装
    将 Dreamweaver2021 压缩包解压到本地:点击蓝色字体下载压缩包提取码ixsu鼠标右键点击 Set-up 选择 以管理员身份运行:点击 更改位置 可以自定义选择安装路径 也可以选择默认位置点击 继续:等待安装正常等待5分钟左右:安装完成点击关闭:双击桌面 Drea......
  • Living-Dream 系列笔记 第75期
    CF126B朴素解法:求出原字符串的最长border,并kmp匹配出出现在中间的最长border,若没有则不断缩短border的长度,直到中间存在。若border长度减到了\(0\),则无解。我们通过画图来探索优化方式。如图,蓝色部分为原串的最长border,红色部分为蓝色部分的最长border。容易发现,......
  • CodeForces-765F
    首先,如果你写过P9058的话,应该会想到支配点对这个trick,我们不妨将此题的套路搬到这套题上.定义点对\((i,j),a_i\lea_j\),当\((i,j)\)被支配当且仅当存在\(i<k<j\)满足\(a_i\lea_k\lea_j\)。相应的,一个有效的点对\((i,j)\),其中\(i\)满足\(i\)最大且\(a_i<a_j\)。......
  • bzoj4767 两双手
    题目传送容斥思想的一道好题。首先我们可以很轻松的将使用\(A,B\)两种移动的次数从而到达一个点通过二元一次方程解出。不妨设分别为\(x,y\)步,这样一来,如果我们不考虑禁止点,方案为\(\binom{x+y}{x}\)。则我们现将给出的禁止点转换为步数\((x,y)\),并排序。但这样显然多算......
  • Living-Dream 系列笔记 第74期
    Kobe-Morris-Pratt算法定义一些基本定义:border:是一个字符串的子串(不与其本身相同)且满足既是其前缀又是其后缀的字符串,我们称之为该字符串的一个border。Kobe-Morris-Pratt算法(以下简称KMP算法),是解决字符串匹配问题的一种算法,实际做题中常偏思维,通常用到的只有其中的bo......
  • android10.0(Q) MTK 6765 user版本打开root权限
    前言相比较Android8.1、9.0而言,Android10.0版本的root变得相当麻烦,10.0中引入了动态分区机制,同样的要想完全adbroot,需要fastboot解锁,然后关闭verity才能adbremount成功。我尝试和之前一样修改fstab.in.mt6765中的ro和rw初始值,容易导致无法正常开机,在......
  • 【网站项目】SpringBoot760校园二手交易平台
    ......
  • 【网站项目】SpringBoot760校园二手交易平台
    ......