首页 > 其他分享 >CF631D Messenger (kmp + 字符串处理)

CF631D Messenger (kmp + 字符串处理)

时间:2024-07-01 10:30:58浏览次数:1  
标签:CF631D int tot ++ lst Messenger kmp pretot lsttot

CF631D Messenger

kmp + 字符串处理

思路简单,写起来细节比较多

首先要合并同类项,然后再考虑什么时候 \(s=t\)。如果合并后 \(t\) 有一种或两种字符,那么都可以直接做;大于两种,我们发现匹配的条件为:中间部分完全相同,首尾字符相同并且 \(s\) 首尾字符的数量要大于 \(t\)。

中间部分完全相同等价于字符和出现次数完全相同,所以我们只需要将这两个东西体现在字符串中,然后中间部分做 kmp 匹配,每当匹配到以后,判断两边是否满足条件即可。

复杂度 \(O(n)\)。我的实现不好,所以代码量又大,看上去又丑。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 1800010;
int n, m;
i64 ans;
i64 pretot, suftot;
char pre, suf, k;
std::string s, t;
i64 tot[N], id[N], nxt[N];
char c[200010];
char d[N];
int num;
int main() {
	std::cin >> n >> m;

	i64 lst = -1, lsttot = 0;
	for(int i = 1; i <= n; i++) {
		char a, b;
		std::cin >> tot[i] >> b >> a;

		if(lst == -1) lst = a, lsttot = tot[i];
		else if(lst == a) {
			lsttot += tot[i];
		} else {
			s += lst;
			char x[20];
			sprintf(x, "%lld", lsttot);
			s += x;
			c[++num] = lst;
			tot[num] = lsttot;
			lsttot = tot[i];
			lst = a;
		}
	}
	if(lst != -1) {
		s += lst;
		char x[12];
		
		sprintf(x, "%lld", lsttot);
		s += x;
		c[++num] = lst;
		tot[num] = lsttot;
	} //合并同类项
    
	s = "#" + s;
	int nw = 1, slen = s.length() - 1;
	for(int i = 1; i <= num; i++) {
		int j = nw;
		for(; j <= slen; j++) {
			if(s[j] >= 'a' && s[j] <= 'z' && s[nw] != s[j]) break;
			id[j] = i; 
			d[j] = c[i];
		}
		nw = j;
	}
    
	int flg = 0;
	lst = -1, lsttot = 0;
	for(int i = 1; i <= m; i++) {
		char a, b;
		int v;
		std::cin >> v >> b >> a;

		if(lst == -1) lst = a, lsttot = v;
		else if(lst == a) {
			lsttot += v;
		} else {
			if(!flg) pre = lst, pretot = lsttot, flg++, lst = a, lsttot = v;
			else {
				t += lst;
				char x[20];
				sprintf(x, "%lld", lsttot);
				t += x;
				lsttot = v;
				lst = a;
				flg++;
			}
		}
	}
	if(lst != -1) {
		suf = lst, suftot = lsttot;
		flg++;
	} //合并同类项
	t = "#" + t;
    
	if(flg == 1) {
		pre = (pre | suf), pretot = (pretot | suftot);
		for(int i = 1; i <= num; i++) {
			if(c[i] == pre && tot[i] >= pretot) ans += 1LL * (tot[i] - pretot + 1);
		}
		std::cout << ans << "\n";
		return 0;
	} else if(flg == 2) {
		for(int i = 1; i < num; i++) {
			if(c[i] == pre && tot[i] >= pretot && c[i + 1] == suf && tot[i + 1] >= suftot) ans++;
		}
		
		std::cout << ans << "\n";
		return 0;
	} //特判

	int tlen = t.length() - 1;
	for(int i = 2, j = 0; i <= tlen; i++) {
		while(j && t[i] != t[j + 1]) j = nxt[j];
		if(t[i] == t[j + 1]) j++;
		nxt[i] = j;
	}
	for(int i = 1, j = 0; i <= slen; i++) {
		while(j && s[i] != t[j + 1]) j = nxt[j];
		if(s[i] == t[j + 1]) j++;
		if(j == tlen) {
			if(tot[id[i + 1]] >= suftot && d[i + 1] == suf) {
				if(tot[id[i - tlen]] >= pretot && d[i - tlen] == pre) ans++;
			} 
		} 
	} //普通情况

	std::cout << ans << "\n";

	return 0;
}

标签:CF631D,int,tot,++,lst,Messenger,kmp,pretot,lsttot
From: https://www.cnblogs.com/FireRaku/p/18277543

相关文章

  • [字符串专题] KMP、Hash、Trie
    KMP核心思想:在每次失配时,不是把p串往后移一位,而是把p串往后移动至下一次可以和前面部分匹配的位置,这样就可以跳过大多数的失配步骤。而每次p串移动的步数就是通过查找next数组确定的。KMP主要分两步:求next数组、匹配字符串,其难点在于如何求next数组for(inti=1,......
  • day09 | KMP算法笔记
    目录一、KMP算法有什么用?二、构建next数组(就是前缀表)1)什么是前缀表(next数组)2)前缀表有什么用3)前缀表怎么记录的?4)为什么一定要用前缀表5)构建next数组三、力扣28.实现strStr()四、拓展题重复的子字符串一、KMP算法有什么用?该算法主要应用在字符串匹配上,当模式串与......
  • KMP
    前缀函数给定一个长度为\(n\)的字符串\(s\)(设下标从\(1\)开始),其前缀函数定义为一个长度为\(n\)的整数数组\(\pi\),其中\(\pi_i\)满足:\(s[1,\pi_i]=s[n-\pi_i+1,n]\)且\(\pi_i\nen\)。如果没有为\(0\)。最朴素的方法求\(\pi\)时间复杂度为\(O(n^3)\)。优......
  • 模式匹配---kmp算法
    模式匹配--Kmp算法暴力匹配暴力匹配,既普通模式匹配,主串一个一个地与子串进行比对,一旦匹配失败就跳回主串原指针的下一个重新回溯,子串跳回第一个,重新开始匹配。主串BABCBFDAB下标012345678子串BCB主串原指针指向下标为......
  • KMP算法
    KMP算法KMP算法是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的经典算法。重点是找到字符串的最长公共前后缀。用最长公共前后缀在匹配的同时,实现快速跳转。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintINF=0x3f3f3f3f;......
  • 算法课程笔记——KMP&字符串哈希
    算法课程笔记——KMP&字符串哈希就是模板题aba是前后缀,真前后缀就只有a/b /a避免出现不同字符有相同的值相当于进制如果你能熟练掌握正则表达式,用库还能更快......
  • 数据结构中的算法-KMP算法
    一、KMP算法串的模式匹配操作是指在当前串(主串)中寻找子串(模式串)的过程。当在主串中找到了和模式串相同的子串时,模式匹配成功;否则,模式匹配失败。当模式匹配成功时,返回模式串的首字符在主串中的位置;否则,返回-1。1.1暴力模式匹配算法(Brute-Force)假设有主串S和模式串T,T的长度为......
  • kmp的神奇之处
    $kmp$想必大家都不陌生,这里先贴个模板hh从0开始:for(inti=1,j=0;i<s2.length();i++){while(j&&s2[i]!=s2[j])j=ne[j-1];if(s2[i]==s2[j])j++;ne[i]=j;}for(inti=0,j=0;i<s1.l......
  • 【字符串常用算法】——KMP算法(你别闲烦 超详细,给你解释明白)
    1、字符串匹配——KMP算法    当我们想要想要在一个字符串中找到一个子串,如在字符串"aaabaaacaaad"中查找是否存在模式串"aaad"。首先常规的算法如下:1、先比较字符串与模式串 第一个是否相等,相等则匹配下一个2、比较第二个字符是否相等,相等则匹配下一个3、比......
  • 第二题-塔子哥的编译原理实验【KMP】
    本题的模式串可以展开,使用栈来模拟即可,每次一个(放入栈中对应的位置以及前面的数量,每次)弹出栈顶元素,然后将栈顶元素的数量乘以当前的字符串加上栈顶元素的前面的字符串加入到模式串中即可。需要注意有可能模式串非常长,所以中间需要判断是否已经超过了匹配串的长度,超过则直接返......