Did We Get Everything Covered? Codeforces Round 921 (Div. 2) 1925C

Problem - C - Codeforces

题目大意:给出一个长度为m的字符串s,问所有长度为n且由字母表中前k个字母组成的字符串是否都是s的子序列,如果不是须给出反例

1<=n<=26;1<=k<=26;1<=m<=1000;所有样例的m之和不超过1e6

思路:先回顾一下A题是怎么做的,也就是构造一个最短的字符串S使所有长度为n且由字母表中前k个字母组成的字符串都是S的子序列。

当n等于1时,显然我们要让k个字母各自出现一次,顺序任意,我们称这个长度为k的字符串为一个合法段。当n等于2时,k个字母各出现一次后,所有字母还要再出现一次,所以最短的合法字符串就是前后各一个合法段拼在一起,每个合法段内部的字母顺序不影响。同理,n等于几就要有几个合法段。

那么我们可以尝试在s中找合法段,每当k个字母都至少出现一次就是一个合法段,如果找到了n个合法段,就是YES,否则就是NO,然后考虑怎么找反例

因为每个合法段中可能夹杂着其他的字母,比如k=3时aabbcc是一个合法段,那么要排除多余字母的影响,就应该选取这个合法段中最后一个字母加入到反例中。s遍历完了之后再将最后一个合法段中没出现的一个字母加入反例中,这样的反例在s中一定没出现过。如果不够n的话再随便找k以内的字母凑即可

cpp 复制代码
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
ll n;
bool vis[N];
void init()
{
	for (int i = 1; i <= 26; i++)
	{//注意初始化
		vis[i] = 0;
	}
}
void solve()
{
	cin >> n;
	init();	
	int k;
	cin >> k;
	int m;
	cin >> m;
	string s;
	cin >> s;
	int j = 0;
	char las;
	string ans;
	bool flag = 1;
	for (int i = 1; i <= n; i++)
	{//找到n个合法段
		int cnt = 0;
		for (;j < m; j++)
		{//遍历s
			if (!vis[s[j]-'a'+1])
			{//找到第一次出现的字母
				vis[s[j]-'a'+1] = 1;
				cnt++;
				if (cnt == k)
				{//找到了一个合法段
					las = s[j];
					ans += las;//将最后一个字母放入
                    for (int ii = 1; ii <= k; ii++)
			            {
				            vis[ii] = 0;
			            }
			        j++;
					break;
				}
			}
		}
		if(cnt != k)
		{//找不到合法段了						
			flag = 0;
			for (int ii = 1; ii <= k; ii++)
			{
				if (!vis[ii])
				{//找到一个没出现的字母,加入反例中
					ans+= char('a' + ii - 1);
					break;
				}
			}			
		}
	}
	if (!flag)
	{
		cout << "NO\n";
		for (int i = 0; i < ans.length(); i++)
		{
			cout << ans[i];
		}
		cout << '\n';
		return;
	}
	cout << "YES";
	cout << '\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;	
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}
相关推荐
草履虫建模12 分钟前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq2 小时前
分布式系统安全通信
开发语言·c++·算法
Jasmine_llq3 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
学嵌入式的小杨同学3 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
爱吃rabbit的mq3 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
精彩极了吧3 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
(❁´◡`❁)Jimmy(❁´◡`❁)4 小时前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi4 小时前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
CSDN_RTKLIB4 小时前
【四个场景测试】源文件编码UTF-8 BOM
c++
不能隔夜的咖喱5 小时前
牛客网刷题(2)
java·开发语言·算法