【题解】【CF631D】Messenger

本文介绍了一种利用KMP算法进行高效字符串匹配的方法,特别适用于处理由结构化的块组成的大规模字符串数据。文中详细解释了如何通过比较两个字符串的特定属性来判断一个字符串是否为另一个字符串的子串,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们定义S[i]代表S的第i块,T[i]代表T的第i块。

同时S[l..r]代表S的l到r位,并且,T[l..r]代表T的l到r位。

若T是S的字串,则S[l + 1..r - 1]=T[2..m - 1]且S[l].l = T[1].l且S[l].c ≥ T[1].c且S[r].l = T[m].l且S[r].c ≥ T[m].c.

所以我们只需要找到T[2..m-1]SS 中出现的地方,然后再检查一下边界,这可以用KMP算法解决。

另外:

  1. M=1M=2的情况可以特殊处理

  2. 若相邻的两块所含的字符相同,则可以合并

  3. 答案需要储存在long long中

Time: O(n+m)

Memory: O(n+m)

代码:

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

#define ll long long

struct dat{
	ll l;
	char c;
	friend bool operator<=(const dat &d1,const dat &d2)
	{
		return (d1.c==d2.c) && (d1.l<=d2.l);
	}
	friend bool operator==(const dat &d1,const dat &d2)
	{
		return (d1.c==d2.c) && (d1.l==d2.l);
	}
}a[200001],b[200001];

int f[200001],n,m;

void cp(dat *a,int &n)
{
	int m=0;
	for(int i=0;i<n;++i)
	{
		if(m==0 || a[m-1].c!=a[i].c)
			a[m++]=a[i];
		else
			a[m-1].l+=a[i].l;
	}
	n=m;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)scanf("%lld-%c",&a[i].l,&a[i].c);
	for(int i=0;i<m;++i)scanf("%lld-%c",&b[i].l,&b[i].c);
	cp(a,n);
	cp(b,m);
	ll ans=0;
	switch(m) {
		case 1:{
			for(int i=0;i<n;++i)
            if (b[0]<=a[i])
                ans+=a[i].l-b[0].l+1;
			break;
		}
		case 2:{
			for(int i=0;i<n-1;++i)
            if (b[0]<=a[i]&&b[1]<=a[i + 1])
                ++ans;
			break;
		}
		default:{
			f[1]=0;
        	for(int i=2;i<m-1;i++) {
	            int j=f[i-1];
	            while(j>0&&!(b[j+1]==b[i]))
	                j=f[j];
	            if (b[j+1]==b[i])
	                j++;
	            f[i]=j;
	        }
	        for(int i=1,j=0;i<n-1;i++){
	            while (j>0 && !(b[j+1]==a[i]))
	                j=f[j];
	            if(b[j+1]==a[i])
	                j++;
	            if(j==m-2)
				{
	                if(b[0]<=a[i-j] && b[j+1]<=a[i+1])
	                    ans++;
	                j=f[j];
	            }
	        }
		}
	}
	printf("%lld\n",ans);
}


CF Directional Increase是一道经典的算法题目,通常出现在编程竞赛中。题目要求在一个二维网格中,找到从起点到终点的路径,使得路径上的数值递增。以下是详细的题解: ### 题目描述 给定一个二维网格,每个格子中有一个整数。起点在左上角,终点在右下角。你可以从当前格子移动到右边的格子或下边的格子。找到一条路径,使得路径上的数值递增。 ### 解题思路 1. **动态规划**:使用动态规划来解决问题。定义一个二维数组`dp[i][j]`,表示从起点到格子`(i, j)`的递增路径的长度。 2. **初始化**:起点`dp[0][0]`的值为`grid[0][0]`。 3. **状态转移方程**: - 如果从上方移动到当前格子`(i, j)`,则`dp[i][j] = max(dp[i][j], dp[i-1][j] + 1)`,前提是`grid[i][j] > grid[i-1][j]`。 - 如果从左方移动到当前格子`(i, j)`,则`dp[i][j] = max(dp[i][j], dp[i][j-1] + 1)`,前提是`grid[i][j] > grid[i][j-1]`。 ### 代码实现 ```python def directional_increase(grid): if not grid or not grid[0]: return 0 m, n = len(grid), len(grid[0]) dp = [[1] * n for _ in range(m)] for i in range(m): for j in range(n): if i > 0 and grid[i][j] > grid[i-1][j]: dp[i][j] = max(dp[i][j], dp[i-1][j] + 1) if j > 0 and grid[i][j] > grid[i][j-1]: dp[i][j] = max(dp[i][j], dp[i][j-1] + 1) return dp[m-1][n-1] # 示例 grid = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] print(directional_increase(grid)) # 输出: 5 ``` ### 解释 - 初始化`dp`数组为全1,因为每个格子的递增路径至少为1。 - 遍历每个格子,更新`dp[i][j]`的值。 - 最后,`dp[m-1][n-1]`即为从起点到终点的递增路径的最大长度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值