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

Living-Dream 系列笔记 第59期

时间:2024-06-08 21:54:44浏览次数:19  
标签:Living 59 int hs ht len hash Dream dp

T1

这是一道 manacher 模板,但是我们使用 二分 + hash \(O(n \log n)\) 的做法。

显然地,若长为 \(len\) 的回文串存在,则长为 \(len-2,len-4,...\) 的回文串也一定存在(在两端各删去若干相同字符即可)。

至此,我们发现回文串分两类:奇回文串、偶回文串,在每一类当中分别具有单调性。

于是我们对于同一对称轴,进行两遍二分,check 用 hash 判回文即可。

奇、偶回文串对于答案的贡献即为 \(l \times 2\) 和 \(l \times 2 + 1\)。

于是我们得到了 24 pts。

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

const int N=1e7+5;
const int BASE=13331;
int n,ans=-1e9;
string s,t;
ull hs[N],ht[N],p[N];

void init_hash(){
	p[0]=1;
	for(int i=1;i<=n;i++) p[i]=p[i-1]*BASE;
	for(int i=1;i<=n;i++) hs[i]=hs[i-1]*BASE+s[i];
	for(int i=n;i>=1;i--) ht[i]=ht[i+1]*BASE+s[i];
}
int get_hs(int l,int r){
	return hs[r]-hs[l-1]*p[r-l+1];
}
int get_ht(int l,int r){
	return ht[l]-ht[r+1]*p[r-l+1];
}

signed main(){
	cin>>s,n=s.size(),s='#'+s;
	init_hash();
	for(int i=1;i<=n;i++){
		int l=0,r=min(i-1,n-i+1)+1; 
		while(l+1<r){
			int mid=(l+r)>>1;
			if(get_hs(i-mid,i-1)==get_ht(i,i+mid-1)) l=mid;
			else r=mid;
		}
		ans=max(ans,l*2);
		l=0,r=min(i-1,n-i)+1;
		while(l+1<r){
			int mid=(l+r)>>1;
			if(get_hs(i-mid,i-1)==get_ht(i+1,i+mid)) l=mid;
			else r=mid;
		}
		ans=max(ans,l*2+1);
	}
	cout<<ans;
	return 0;
} 

T2/T3

很妙的一道题阿。

我们钦定含通配符的字符串为 \(S\),文件名列表里的当前字符串为 \(T\)。

我们注意到询问仅关心是否匹配上了,考虑 dp。

我们又发现通配符个数 \(\le 10\),考虑按通配符划分状态。

令 \(dp_{i,j}\) 表示 \(S\) 以第 \(i\) 个通配符结尾,\(T\) 以第 \(j\) 个字符结尾时是否能匹配上。

初始状态:\(dp_{0,0}=1\),答案:判断 \(dp_{tot,\mid T \mid}\)(\(tot\) 表示 \(S\) 中通配符个数,\(|T|\) 表示 \(T\) 的长度)。

转移:

  • 若当前通配符为 *

    若 \(dp_{i,j-1}=1\),则 \(dp_{i,j}=1\)(不停往下扩展,因为 * 可以包含任意个字符)

  • 否则

    枚举与之匹配的 \(T\) 中的与其长度相同的子串,用 hash 检测是否相同,

    • 若下一个通配符为 ?

      \(dp_{i+1,j+len+1} = 1\)(延长一个也可匹配成功)

    • 否则

      \(dp_{i+1,j+len}=1\)

一些细节见代码。

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

const int N=1e5+5,M=15;
const int BASE=13331;
int n;
ull hs[N],ht[N],p[N];
bool dp[M][N];
string s;
vector<int> pos;

void init_hash(){
	p[0]=1;
	for(int i=1;i<=N;i++) p[i]=p[i-1]*BASE;
	for(int i=1;i<s.size();i++) hs[i]=hs[i-1]*BASE+s[i];
}
ull get_hs(int l,int r){
	return hs[r]-hs[l-1]*p[r-l+1];
}
ull get_ht(int l,int r){
	return ht[r]-ht[l-1]*p[r-l+1];
}
string sol(string t){
	memset(dp,0,sizeof(dp)),dp[0][0]=1;
	t='#'+t+'#';
	for(int i=1;i<t.size();i++) ht[i]=ht[i-1]*BASE+t[i];
	for(int i=0;i<pos.size();i++){
		if(s[pos[i]]=='*')
			for(int j=1;j<t.size();j++)
				if(dp[i][j-1]) dp[i][j]=1;
		for(int j=0;j<t.size();j++){
			if(!dp[i][j]) continue;
			int st=pos[i]+1,ed=pos[i+1]-1,len=ed-st+1;
			if(j+len<t.size()&&get_hs(st,ed)==get_ht(j+1,j+len)){
				if(s[pos[i+1]]=='?') dp[i+1][j+len+1]=1;
				else dp[i+1][j+len]=1;
			}
		}
	}
	if(dp[pos.size()-1][t.size()-1]) return "YES";
	else return "NO"; 
}

int main(){
	cin>>s>>n;
	s='#'+s+'?',pos.push_back(0);
	for(int i=1;i<s.size();i++)
		if(s[i]=='*'||s[i]=='?') pos.push_back(i);
	init_hash();
	while(n--){
		string t; cin>>t;
		cout<<sol(t)<<'\n';
	}
	return 0;
}

T3 是双倍经验。

作业 T1

求方案数,考虑 dp。

我们钦定碱基串为 \(S\),当前选的碱基序列为 \(T\)。

令 \(dp_{i,j}\) 表示前 \(i\) 个集合选出的字符串拼接起来后与 \(s_{1 \sim j}\) 的匹配方案数。

初始状态:\(dp_{0,i}=1\),答案:\(\sum dp_{k,i}\)。

转移:

\[dp_{i,j}=(dp_{i,j}+dp_{i-1,j-len}) \bmod 10^9 +7 \]

(\(len\) 为 \(T\) 的长度)

条件:

\[hs(j-len+1,j)+ht \]

(\(hs(l,r)\) 表示 \(S_{l \sim r}\) 的 hash value,\(ht\) 表示 \(T\) 的 hash value)

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

const int K=1e2+5,A=11,S=1e4+5;
const int MOD=1e9+7,BASE=13331;
int n,k,ans;
int dp[K][S],a[K];
ull hs[S],ht[K][A],p[S];
string s,t[K][A];

void init_hash(){
	p[0]=1;
	for(int i=1;i<=n;i++) p[i]=p[i-1]*BASE;
	for(int i=1;i<=n;i++) hs[i]=hs[i-1]*BASE+s[i];
	for(int i=1;i<=k;i++)
		for(int j=1;j<=a[i];j++)
			for(int p=1;p<t[i][j].size();p++)
				ht[i][j]=ht[i][j]*BASE+t[i][j][p];
}
ull get_hs(int l,int r){
	return hs[r]-hs[l-1]*p[r-l+1];
}

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],t[i][j]='#'+t[i][j];
	}
	init_hash();
	for(int i=0;i<=n;i++) dp[0][i]=1;
	for(int i=1;i<=k;i++){
		for(int j=1;j<=n;j++){
			for(int u=1;u<=a[i];u++){
				int len=t[i][u].size()-1;
				if(j>=len&&get_hs(j-len+1,j)==ht[i][u])
					dp[i][j]=(dp[i][j]+dp[i-1][j-len])%MOD;
			}
		}
	}
	for(int i=1;i<=n;i++) ans=(ans+dp[k][i])%MOD;
	cout<<ans;
	return 0;
}

标签:Living,59,int,hs,ht,len,hash,Dream,dp
From: https://www.cnblogs.com/XOF-0-0/p/18239005

相关文章

  • Q14 LeetCode59 螺旋矩阵
    1.二维数组声明  int[][]ans=newint[n][n];2. left<=right&&top<=bottom 跳出循环条件 1classSolution{2publicint[][]generateMatrix(intn){3int[][]ans=newint[n][n];4intnum=1;5inttop=0,bottom=n-1,left......
  • LeetCode 2559. 统计范围内的元音字符串数
    2559.统计范围内的元音字符串数给你一个下标从 0 开始的字符串数组 words 以及一个二维整数数组 queries 。每个查询 queries[i]=[li,ri] 会要求我们统计在 words 中下标在 li 到 ri 范围内(包含 这两个值)并且以元音开头和结尾的字符串的数目。返回一个整......
  • 2559. 统计范围内的元音字符串数(前缀和) o(n)时间复杂度
    给你一个下标从 0 开始的字符串数组 words 以及一个二维整数数组 queries 。每个查询 queries[i]=[li,ri] 会要求我们统计在 words 中下标在 li 到 ri 范围内(包含 这两个值)并且以元音开头和结尾的字符串的数目。返回一个整数数组,其中数组的第 i 个元素对......
  • CH582,CH592,CH57x系列芯片看门狗中断使用示例
    #include"CH58x_common.h"/**********************************************************************@fnDebugInit**@brief调试初始化**@returnnone*/voidDebugInit(void){GPIOA_SetBits(GPIO_Pin_9);GPIOA_ModeCfg(GPIO_Pin......
  • 代码随想录第2天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,数组总结
    题目:977.有序数组的平方思路:first.for循环,平方,然后sort排序,提交通过啊哈~|但时间复杂度大O(n+nlogn),->O(nlogn)的时间复杂度,题目进阶要求时间复杂度为O(n)second.双指针。题目为有序数组,包含负数,则平方后,最大值在数组的两头,则使用双指针进行,两个比较大小,大的存入新......
  • (第26天)【leetcode题解】226、翻转二叉树 589、N叉树的前序遍历 590、N叉树的后序遍
    目录226、翻转二叉树题目描述思路代码589、N叉树的前序遍历题目描述思路代码590、N叉树的后序遍历题目描述思路代码思考总结226、翻转二叉树题目描述给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。示例:输入:root=[4,2,7,1,3,6,9]输出:[4,7,2,9,......
  • 算法训练营第九天|28. 实现 strStr()459.重复的子字符串 字符串总结 双指针回顾
    28.实现strStr()1.暴力解法:对主串的每一个字符都作为开头,尝试是否匹配字串,时间复杂度O(m*n)2.确保所有的变量在使用前都被明确地初始化了3.kmp算法之后慢慢理解!!!要记得!!!459.重复的子字符串1.暴力解法:列出所有的子字符串,看是否合法(子字符串开头固定),时间复杂度O(n*n)2.用模......
  • 计算机毕业设计项目推荐,28259校园信息交流平台的设计与实现(开题答辩+程序定制+全套文
    摘 要随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,校园信息交流平台被用户普遍使用,为方便用户能够可以随时进行校园信息交流平台的数据信息管理,特开发了基于校园信息交流......
  • 51单片机学习记录-06-LED点阵屏(74HC595移位寄存器)
    1 74HC595是串行输入并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于IO口扩展。2 74HC595原理图上升沿移位SERCLK,上升沿锁存RCLK点阵屏MATRIX函数sbitRCK=P3^5; //RCLKsbitSCK=P3^6; //SRCLKsbitSER=P3......