Living-Dream 系列笔记 第75期

news/2025/3/13 11:18:09/文章来源:https://www.cnblogs.com/XOF-0-0/p/18344940

CF126B

朴素解法:求出原字符串的最长 border,并 kmp 匹配出出现在中间的最长 border,若没有则不断缩短 border 的长度,直到中间存在。若 border 长度减到了 \(0\),则无解。

我们通过画图来探索优化方式。

如图,蓝色部分为原串的最长 border,红色部分为蓝色部分的最长 border。

容易发现,红色部分就是我们要求的答案。

然后就做完了。具体实现细节见代码。

code
#include<bits/stdc++.h>
using namespace std;const int N=1e6+5;
string str;
int nxt[N],nxt2[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;elsej=nxt[j];}
}
int kmp(string s,string t){getnxt(t); //注意还得求一遍 nxtint i=0,j=0;for(;i<s.size();){if(j==t.size()-1&&s[i]==t[j])return i-j+1; //直接 return 是为了找中间出现的,最后 return 会找到后缀if(j==-1||s[i]==t[j])i++,j++;elsej=nxt[j];}return 0;
}int main(){ios::sync_with_stdio(0);cin>>str;getnxt(str);int last=str.size()-nxt[str.size()];string t=str.substr(last); //后缀(即最长 border)memcpy(nxt2,nxt,sizeof nxt2);int pos=kmp(str.substr(1),t); //str.substr(1) 是为了不取到前缀if(pos<last){if(t=="") cout<<"Just a legend",exit(0);cout<<t,exit(0);}pos=nxt2[nxt2[str.size()]];if((!pos)||(!nxt2[str.size()]))cout<<"Just a legend",exit(0);t=str.substr(0,pos);cout<<t;return 0;
}

P4824

朴素解法:每次 kmp 匹配出 \(T\) 的出现位置并删除直到 \(S\) 中不含有 \(T\) 即可。

我们通过发掘性质来探索优化方式。

观察这样一组数据:

momomoooo
moo

我们的操作方式是:

" momo 'moo' oo " -> " mo 'moo' o " -> " 'moo' " -> ""

可以发现,起始位置越靠后的子串,越先被消除,考虑使用栈进行维护。

具体的,我们记录 \(match_i\) 表示 \(S\) 中的每一个 \(i\),它要跳到的 \(T\) 中的下一个位置,这显然可以在 kmp 匹配的过程中维护。

同时,我们也用栈维护当前的 \(S\) 串。

每当一个 \(T\) 匹配成功后,栈弹出 \(\left| T \right|\) 个字符,并令 \(j\) 跳到此时栈顶所对应的 \(match\)

code
#include<bits/stdc++.h>
using namespace std;const int N=1e7+5;
string str1,str2;
int top,nxt[N],stk[N],match[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;elsej=nxt[j];}
}
int kmp(string s,string t){getnxt(t);int i=0,j=0;for(;i<s.size();){if(j==-1||s[i]==t[j])match[i]=j+1,stk[++top]=i,i++,j++;elsej=nxt[j];if(j==t.size())top-=t.size(),j=match[stk[top]];}
}int main(){ios::sync_with_stdio(0);cin>>str1>>str2;kmp(str1,str2);for(int i=1;i<=top;i++)cout<<str1[stk[i]];return 0;
}

P3435

首先,画图并发掘性质

如图,\(Q\) 串是 \(P\) 串的一个周期。

显然 \(Q=P-红色部分\),而要使得 \(Q\) 最长,则红色部分一定最短。结合图分析,可将题目转化为求 \(P\) 的最短 border。

如何求最短 border?接下来我们专门研究 \(P\) 串。

如图,我不停地求出 \(P\) 串的 最长 border 的最长 border 的最长 border ...... 如此循环往复,容易发现最长 border 总是成对出现,且一定会有两个分别在 \(P\) 串的一头一尾。这样便一定能求出 \(P\) 的最短 border。

但是一步一步跳太慢了,我们加个记忆化即可。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N=1e7+5;
int n,nxt[N];
string str;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;elsej=nxt[j];}
}signed main(){ios::sync_with_stdio(0);cin>>n>>str;int ans=0;getnxt(str);for(int i=2,j=2;i<=n;i++){j=i;while(nxt[j])j=nxt[j];if(nxt[i]!=0)nxt[i]=j; //记忆化ans+=i-j;}cout<<ans;return 0;
}

CF494B

参考了 RainFestival 的题解。/bx/bx/bx

求方案数却不求具体方案,考虑 dp。

\(dp_i\) 表示分割方案的最后一个子串以 \(s_i\) 结尾的方案数(结尾定义状态)。

初始:\(dp_0=1\)(一个字符也有一种方案)。

转移:

\[dp_i=\sum_{j=1}^{i} \sum_{k=0}^{j-1}[t \in s_{j \sim i}]dp_k \]

\([x]\) 表示在条件 \(x\) 满足的情况下。

\(s \in t\) 表示 \(s\)\(t\) 的子串。

\(i\) 满足 \(i \in [1,n]\)

朴素转移是 \(O(n^3)\) 的(需要预处理 \([t \in s_{j \sim i}]\))。

容易发现,若在每个 \(i\) 之前找到一个最大的 \(y\) 使得 \(y+\left|t\right|-1 \le i\)\(t \in s_{y \sim y+\left|t\right|-1}\),则所有满足 \(j \le y\)\(j\) 才会满足 \(t \in s_{j \sim i}\)。其中 \(y\) 可以使用 kmp 求出。

于是转移变为:

\[dp_i=\sum_{j=1}^{d_i} \sum_{k=0}^{j-1}dp_k \]

还是 \(O(n^3)\),但快了一点。

考虑将式子变形。

\[dp_i=\sum_{j=1}^{d_i} \sum_{k=0}^{j-1}dp_k \]

\[dp_i=\sum_{j=0}^{d_i-1} \sum_{k=j+1}^{d_i}dp_k \]

(将掌管求和下标的求和符号提到里面来,方便化简)

\[dp_i=\sum_{j=0}^{d_i-1} dp_j \times (d_i-j) \]

(化简求和符号)

令:

\[\begin{cases} f_i=\sum_{j=0}^{i} dp_j\\ s_i=\sum_{j=0}^{i} dp_j \times j \end{cases} \]

则:

\[dp_i=d_i \times f_{d_i-1}-s_{d_i-1} \]

初始:

\[\begin{cases} f_1=1\\ s_1=0\\ dp_1=1 \end{cases} \]

code
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N=1e5+5;
const int MOD=1e9+7;
string s,t;
int d[N],tag[N],nxt[N];
int dp[N],ff[N],ss[N];void getnxt(string y){int i=0,j=-1;nxt[0]=-1;for(;i<y.size();){if(j==-1||y[i]==y[j])i++,j++,nxt[i]=j;elsej=nxt[j];	}
}
void kmp(string x,string y){getnxt(y);int i=0,j=0;for(;i<x.size();){if(j==-1||x[i]==y[j])i++,j++;elsej=nxt[j];if(j==y.size())tag[i]=1,j=nxt[j];}
}signed main(){ios::sync_with_stdio(0);cin>>s>>t;kmp(s,t);d[0]=0;for(int i=1;i<=s.size();i++)d[i]=(tag[i]?i-t.size()+1:d[i-1]);dp[0]=1,ff[0]=1,ss[0]=0;for(int i=1;i<=s.size();i++){if(!d[i]) dp[i]=0;else dp[i]=((ff[d[i]-1]*d[i]%MOD-ss[d[i]-1])%MOD+MOD)%MOD;ff[i]=(ff[i-1]+dp[i])%MOD;ss[i]=(ss[i-1]+dp[i]*i%MOD)%MOD;}cout<<((ff[s.size()]-1)%MOD+MOD)%MOD; //这里减一是因为 ff 和 dp 的初始值都是一,转移时会重复加return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/778683.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Salesforce常见的100+个业内术语!(系列二)

在上周的文章中,我们开启了Salesforce业内术语的科普和盘点,并介绍了各领域通用的一些术语。前文指路👉Salesforce常见的100+个业内术语!(系列一) 本篇文章将继续与学习者们分享Salesforce Admin和Sales领域的专业术语。 Admin领域的术语 CRED 全称:Create, Read, Edit…

【日记】为啥家族原发性高血压的人还喜欢喝酒啊……(442 字)

正文今天跟人吵了一下午架,因为有一张报表换了新表,所有人都不知道怎么报。上级行一个想法,我一个想法。吵完都发现对方说得有道理,于是决定明天问省分行。难绷。草台班子。鱼儿说他最近喜欢上了喝酒。我们劝他的同时,我想起来前两天和斯逛超市。本来我觉得高兴,也想着拿…

navicat [IM002][Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序 (0)

1.情景展示 使用navicat连接SQL Server数据库,报错信息如下: [IM002][Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序 (0)2.解决方案 方案1 找到Navicat的安装路径,然后找到sqlncli_x64.msi文件并安装,安装成功后重启Navicat重新进行连接,看是否…

python绘制圆柱体

import os import randomimport numpy as np import matplotlib.pyplot as plt #合成管道数据集def plot_cylinder(center, radius, height, num_points=100):# 生成圆柱体的侧面点坐标theta = np.linspace(0, 2*np.pi, num_points)intervalZ = np.floor(height/0.05)indx2 = […

ComfyUI插件:efficiency-nodes-comfyui节点

前言: 学习ComfyUI是一场持久战, efficiency-nodes-comfyui是提高工作流创造效率的工具,包含效率节点整合工作流中的基础功能,比如Efficient Loader节点相当于Load Checkpoint+Clip set layer+Load VAE等等的合集,并且该插件提供了更加简便快捷的X/Y对比图,能够使测评工作…

6 大推荐给开发者的无代码工具

通过这篇文章了解——为什么开发者也需要使用无代码?以及 6 个推荐给开发者的最佳无代码开发工具。在不断发展的软件开发领域,无代码工具正迅速普及。 最初,这些工具是为非技术背景的业务用户设计的,而如今,它们对开发者来说也同样不可或缺。 无代码工具结合了效率、灵活性…

Creo 文件小版本:文件后缀出现.1/.2/.3

1.保存文件的小版本:文件保存后不会覆盖原文件,而是产生新的副本文件,且文件名后缀为(**1/***.2/***.3)样式。此功能能够在特殊情况找回先前版本,但会造成文件夹臃肿,可根据自身实际情况和习惯进行设置。设置方法:配置编辑器---save file iterations --- no/yes。

pbootcms网站后台关闭验证码后, 无法登录问题解决方法

最近闲来无事, 在后台将pbootcms的登录验证码关闭了(全局配置 - 配置参数 -安全配置 -后台验证码) 结果问题来了, 第二天登录后台一直提示验证码不能为空。 这不是自己给自己找事吗! 现在想输入验证码,也没有地方输入。 从程序上解决吧 apps\admin\controller\IndexCont…

Spring Boot 中使用 JSON Schema 来校验复杂JSON数据

JSON是我们编写API时候用于数据传递的常用格式,那么你是否知道JSON Schema呢? 在数据交换领域,JSON Schema 以其强大的标准化能力,为定义和规范 JSON 数据的结构与规则提供了有力支持。通过一系列精心设计的关键字,JSON Schema 能够详尽地描述数据的各项属性。然而,仅凭 …

Docker安装oracle19c

1. 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/zhuyijun/oracle:19c2. 创建目录并赋权 mkdir -p /docker/oracle19c/oradatachmod 777 /docker/oracle19c/oradata 3. 构建容器并启动 docker run -d -p 1521:1521 \ -p 5502:5500 \ -e ORACLE_SID=ORCLCDB \ -e…

便捷地发get或者post请求的方法

import org.springframework.http.HttpMethod;import org.springframework.web.client.RestTemplate;

易基因:哺乳动物胎盘DNA甲基化变化和胎儿出生体重的综合分析 | 科研速递

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 出生体重是一个复杂的多因素性状,与后期生活中的健康状况和疾病风险有关。胎盘对胎儿的正常生长至关重要,并负责促进母体和发育中胎儿之间的气体、营养和废物交换。胎盘DNA甲基化变化如何影响胎儿出生体重尚…