首页 > 其他分享 >CF1729G Cut Substrings 题解

CF1729G Cut Substrings 题解

时间:2022-11-02 17:55:14浏览次数:83  
标签:子串 删除 题解 pos 字符串 Substrings CF1729G include dp

CF1729G Cut Substrings

给出两个字符串 \(s,t\),每次可以将字符串 \(s\) 中任意一个为 \(t\) 的子串删除,删除位置的字符变为空格(或理解为无实义)。求最少删除几次可以使得字符串 \(s\) 中不会出现字符串 \(t\),以及在这个最小次数下的方案数。\(1\leq |s|,|t|\leq 500\)。

给出一种与官方题解相同的做法。

题解

首先可以先用字符串匹配算法算出 \(s\) 中每个与 \(t\) 相同的子串的出现位置 \(pos\),记第 \(i\) 次出现的位置为 \(pos_i\)。

定义 \(f_i,dp_i\) 分别为删除以原字符串 \(pos_i\) 下标开始的与 \(t\) 相同的子串后,使得字符串 \({1\sim pos_i}\) 下标范围内对应新字符串中不存在 \(t\) 子串的最小操作数和方案数。

假设删除 \(pos_i\) 开始的一个子串后,存在一个 \(j>i\),使得原字符串下标 \(pos_i\sim pos_j-1\) 范围内对应的新的字符串中不存在一个 \(t\)。那么可以得到转移。

\[f_j\gets f_i+1\\ dp_j\gets \begin{cases}\begin{align} dp_i &\quad f_i\neq f_i+1\\ dp_i+dp_j&\quad f_j=f_i+1 \end{align}\end{cases} \]

实现

假设 \(pos\) 位置一共有 \(tot\) 个,容易发现 \(pos_{tot}\) 开始的子串不一定要被删除。所以我们建立一个必须被删除的无实义节点 \(pos_{tot+1}=n+m\)。最后输出 \(f_{tot}-1\) 和 \(dp_{tot}\)。

现在的问题是找到满足条件的 \(j\)。

容易发现删除 \(pos_i\) 开始的子串后,\(\forall pos_k\leq pos_{i}+|t|-1\) 均不会作为一个完整的 \(t\) 出现在目前 \(s\) 中。找到最小的 \(l\),使得 \(pos_l>pos_i+|t|-1\),那么 \(pos_l\leq pos_j\leq pos_l+|t|-1\),才能使得 \(pos_l\) 开始的子串不再出现。

其他细节具体见代码,时间复杂度 \(O(n^2)\)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
	while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*f;
}
const ll MOD=1000000007;
const int N=503;
char s[N],t[N];
int n,m,f[N],pos[N],tot;
ll dp[N];
inline void Tesc(){
	memset(f,0x3f,sizeof(f));
	memset(dp,0,sizeof(dp));
	scanf("%s%s",s+1,t+1);
	n=strlen(s+1),m=strlen(t+1),tot=0;
	for(int i=1;i+m-1<=n;++i){
		bool flag=1;
		for(int j=1;j<=m;++j)
			if(s[i+j-1]!=t[j])
				{flag=0;break;}
		if(flag)pos[++tot]=i;
	}
	f[0]=0,dp[0]=1;pos[0]=-114514,pos[++tot]=n+m;
	for(int i=0;i<tot;++i){
		int loc=i+1;
		while(loc<=tot&&pos[loc]<=pos[i]+m-1)++loc;
		for(int j=loc;j<=tot&&pos[j]<=pos[loc]+m-1;++j){
			if(f[i]+1<f[j]){
				f[j]=f[i]+1;
				dp[j]=dp[i];
			}else if(f[i]+1==f[j])dp[j]=(dp[j]+dp[i])%MOD;
		}
	}
	printf("%d %lld\n",f[tot]-1,dp[tot]);
}
int main(){
	int T=read();
	while(T--)Tesc();
	return 0;
}

标签:子串,删除,题解,pos,字符串,Substrings,CF1729G,include,dp
From: https://www.cnblogs.com/BigSmall-En/p/16851850.html

相关文章

  • SOJ1669 题解
    题意传送门给定长度为\(N\)的数组\(a\)与\(Q\)个区间,还有一个整数\(M\)。你可以将至多\(M\)个\(a_i\)个变为\(0\),求\[\sum_{i=1}^Q\max_{l_i\lej\ler......
  • CF10E Greedy Change 题解
    http://codeforces.com/problemset/problem/10/E题意给出货币系统\(\{c_n\}\)满足\(c_1>c_2>\cdots>c_n=1\),请找到最小的\(x\)使贪心算法需要的货币数目比最优解多......
  • 未能加载文件或程序集 或它的某一个依赖项。试图加载格式不正确的程序。问题解决
    原因分析:操作系统是64位的,但发布的程序引用了一些32位的ddl,所以出现了兼容性的问题。 解决方案:IIS——应用程序池——高级设置——启用32位应用程序:true。下图这个地方......
  • CSP-S 2022 第二轮 题解
    T1.假期计划(holiday)这个题作为t1可一点都不简单啊。先用bfs\(O(nm)\)求出任意两点之间的最短路,这样就可以判断哪些点对可以排在一起。注意到第1、4个景点是对称的,第......
  • 「题解」Codeforces 1322B Present
    看上去异或里面套了层加法不好拆位,但是依然可以对每个二进制位处理。现在考虑第\(k\)位,那么产生贡献的数字对一定满足以下条件之一:第\(k\)位相同且前\((k-1)\)位......
  • 「题解」Codeforces 930E Coins Exhibition
    看到题就先容斥。然后容斥系数太难算了就寄了,大概要分好几种情况讨论,于是就弃了。不容斥也能做。考虑限制将串划分成了若干段,然后一段一段dp.有没有什么好的方法描述这个......
  • 20221102模拟赛题解
    A-Holy思路由于要让最小值最大,不难想到二分答案。二分后将原矩阵中大于等于\(mid\)的值设为\(1\),小于的设为\(0\),然后将每一行压成二进制,存在两行满足要求当且仅当两......
  • CSP-S 2022 题解
    「CSP-S2022」假期计划\(1\toa\tob\toc\tod\to1\)中\(a,b,c,d\)是\(4\)个不同的景点是突破点,数据范围允许枚举其中的两个。便很自然想到枚举中间的\(b,c\),并......
  • 2022年4月第十三届蓝桥杯省赛C组C语言 习题解析(每日一道)
    试题B:特殊时间   【问题描述】           2022年2月22日22:20是一个很有意义的时间,年份为2022,由3个2和1个0组   成,如果将月和日......
  • 洛谷 P8820 [CSP-S 2022] 数据传输 题解
    首先考虑对于每一次询问暴力DP。设\(f_{u,i}\)表示从\(s\)开始,传到一个到\(u\)距离为\(i\)的点,需要的最短时间。当\(k=3\)时,可能会传到不在\(s\tot\)路......