2024.9.7校测

T1

题目描述

n 只青蛙排成一排,我们将青蛙的不同之处归纳为 K 种特征,比如第 1 种特征表示它是雌性还是雄性,2 号特征代表它是不是青蛙中的长者等。我们将每只青蛙的特征用一个标识符表示,数的二进制表示的第 i 位,表示第 i 种特征,比如一只青蛙的标识符是 13,二进制位 1101,则它有 1,3,4 号特征。

一个平衡的区间是指,选出这一排青蛙中连续的一段,在区间中每种特征出现的次数是一样的。请问这样平衡区间的最大长度是多少?

输入格式

第一行两个数 n,k,表示青蛙的个数和特征的个数。

接下来 n 行,每行一个数,代表青蛙的标识符。

输出格式

一个整数,表示平衡区间的最大长度。

输入样例

7 3
7
6
7
2
1
4
2

输出样例

4

样例解释

[3,6] 这个区间,每种特征出现的次数均为 2

数据规模

对于 30% 数据,n1000

对于 100% 数据, n100000,1K30

T2

题目描述

给出一个敏感词 w,和一篇文章 p,你的工作很简单,每次找出 p 中第一次出现的 w,然后将这个 w 删掉,然后重复这个过程,直到在 p 中找不到 w 为止。请你输出最后删减后的文章 p

输入格式

第一行一个词 w

第二行一篇文章 p

输出格式

输出一行,删减过的文章。

输入样例

abc
aaabcbc

输出样例

a

数据规模

对于 20% 数据,1len(p),len(w)1000

对于 100% 数据,1len(p),len(w)300000

所有字符串均只包括小写字母。

题解

先考虑最朴素的算法,每次用 KMP 找到模式串在文本串中的位置,将它们删掉,讲其它部分拼接起来,重复这个过程直到找不到模式串为止,但这样最坏复杂度为 O(n2),考虑如何优化。

可以发现,删除一个模式串,将前后拼接起来,这个过程很像栈的操作。于是我们考虑一边进行 KMP,一边将当前字符扔入栈,如果匹配上了,就直接将栈中的这个模式串弹出,这样就可以使复杂度降到 O(n),足以通过此题。

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 9;
char a[N], b[N];
int st[N], f[N], g[N], n, m, tot;
int main(){
	freopen("sensitive.in", "r", stdin);
	freopen("sensitive.out", "w", stdout);
    scanf("%s%s", b + 1, a + 1);
    n = strlen(a + 1);
	m = strlen(b + 1);
    for(int i = 2, k = 0; i <= m; i++){
        while(k && b[k + 1] != b[i])
			k = f[k];
        if(b[k + 1] == b[i])
			k++;
        f[i] = k;
    }
    for(int i = 1, k = 0; i <= n; i++){
        while(k && b[k + 1] != a[i])
			k = f[k];
        if(b[k + 1] == a[i])
			k++;
        g[i] = k;
		st[++tot] = i;
        if(k == m){
            tot -= k;
            k = g[st[tot]];
        }
    }
    for(int i = 1; i <= tot; i++)
    	printf("%c", a[st[i]]);
    return 0;
}

T3

题目描述

在网络上,尤其是网络游戏中,一些人出口成脏,影响网络环境。现在给出 n 个关键词 Ti,和一篇待净化的文章 P,请将 P 中的关键词全部用 * 号省略表示。

输入格式

第一行一个数 n,表示关键词的个数。

接下来 n 行,每行一个字符串,表示关键词 Ti

接下来一行,表示文章 P

输出格式

输出净化后的文章。

输入样例

3
trump
ri
o
Donald John Trump (born June 14, 1946) is an American businessman,television personality, author, politician, and the RepublicanParty nominee for President of the United States in the 2016 election. He is chairman of The Trump Organization, which is theprincipal holding company for his real estate ventures and otherbusiness interests.

输出样例

D*nald J*hn ***** (b*rn June 14, 1946) is an Ame**can businessman,televisi*n pers*nality, auth*r, p*litician, and the RepublicanParty n*minee f*r President *f the United States in the 2016 electi*n. He is chairman *f The ***** *rganizati*n, which is thep**ncipal h*lding c*mpany f*r his real estate ventures and *therbusiness interests.

数据规模

sum(t) 为所有关键词长度之和。

对于 20% 数据,len(t),sum(t),len(p),n1000

对于 100% 数据,len(t),sum(t),len(p),n300000

关键词只包括小写字母,不区分大小写。

题解

此问题是典型的多模式串匹配问题,考虑使用 AC 自动机。

为了方便记录哪些字母要被替换成 *,我们在将模式串插入字典树时在每个串的末尾记录一下这个串的长度,在查询时,每跳一个 fail 指针就将这个串所在的区间([(ilen(now)+1),i])打上标记,可以用前缀和优化成 O(1)。输出时,如果该字符被标记了,就输出 *,否则输出该字符

完整代码

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 9;
struct Node{
	int son[26], end, fail, len;
} t[N];
int cnt = 1;
void insert(char *s){
	int now = 0;
	for(int i = 0; s[i]; i++){
		int ch = s[i] - 'a';
		if(t[now].son[ch] == 0)
			t[now].son[ch] = cnt++;
		now = t[now].son[ch];
	}
	t[now].end++;
	t[now].len = strlen(s);
}
void getFail(){
	queue <int> q;
	for(int i = 0; i < 26; i++)
		if(t[0].son[i])
			q.push(t[0].son[i]);
	while(!q.empty()){
		int now = q.front();
		q.pop();
		for(int i = 0; i < 26; i++)
			if(t[now].son[i]){
				t[t[now].son[i]].fail = t[t[now].fail].son[i];
				q.push(t[now].son[i]);
			} else
				t[now].son[i] = t[t[now].fail].son[i];
	}
}
int flag[N];
int query(char *s){
	int ans = 0;
	int now = 0;
	for(int i = 0; s[i]; i++){
		int ch = s[i] - 'a';
		now = t[now].son[ch];
		int tmp = now;
		while(tmp){
			ans += t[tmp].end;
			flag[i + 1]--;
			flag[i - t[tmp].len + 1]++;
			tmp = t[tmp].fail;
		}
	}
	return ans;
}
int n;
char tmp[N];
string s;
int main(){
	freopen("cleanse.in", "r", stdin);
	freopen("cleanse.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){
		scanf("%s", tmp);
		insert(tmp);
	}
	getchar();
	getline(cin, s);
	getFail();
	int len = s.length();
	for(int i = 0; i < len; i++)
		if(s[i] >= 'A' && s[i] <= 'Z')
			tmp[i] = s[i] - 'A' + 'a';
		else
			tmp[i] = s[i];
	int ans = query(tmp);
	for(int i = 1; i < len; i++)
		flag[i] += flag[i - 1];
	for(int i = 0; i < len; i++)
		if(flag[i])
			printf("*");
		else
			printf("%c", s[i]);
	return 0;
}

T4

题目描述

给出一个串 S,求 S 中包含字母 a 的不同的子串有多少个?

输入格式

第一行一个串,表示 S

输出格式

一个整数,表示包含字母 a 的不同的子串的个数。

输入样例1

abc

输出样例1

3

输入样例2

aaa

输出样例2

3

数据规模

对于 30% 数据,len(s)1000

对于 100% 数据,len(s)100000

S 只包含小写字母。

posted @   JPGOJCZX  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示