1. A. Did We Get Everything Covered?(构造、思维)

文章讨论了如何判断一个字符串是否能通过拆分为n段,每段至少包含前k个不同小写字母一次,形成所有可能的长度为n的子序列。给出了判定方法和代码实现,同时指出了一种构造子序列时的常见错误,即不应直接使用字符串长度作为循环条件。
摘要由CSDN通过智能技术生成

1. A. Did We Get Everything Covered?(构造、思维)

题目链接


A. Did We Get Everything Covered?


题意


n , k n,k nk以及长度为 m m m的一个小写的字符串。
字符串的子序列是否包含用前 k k k个小写字母构成的长度为n的字符串的所有情况


题解

  1. 首先判断有没有解:
    要构成所有的字符串,我们可以把原串进行拆分,拆分成n个段,每段如果都包含前k个小写字母至少一次,则说明有解,反之说明无解。
  2. 无解的情况下,考虑如何构造答案。
    用每一段最后一次出现的字符,加上不满足的段中没有出现的字符
    正确性?每一段最后出现的字符一定在前面没出现过,只能在后面出现,这样构造出来的子序列是正确的

代码

#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back

using namespace std;
const int mod=998244353;
void solve() {
	int n,k,m;
	string s;
	cin>>n>>k>>m;
	cin>>s;
	set<char>cnt;
	int cur=0;
	string ans;
	rep(i,0,m-1) {
		cnt.insert(s[i]);
		if(cnt.size()==k) {
			ans+=s[i];
			++cur;
			cnt.clear();
		}
		if(cur>=n) {
			cout<<"YES"<<endl;
			return;
		}
	}
	cout<<"NO"<<endl;
	int len=ans.size();
	rep(i,0,k-1) {
		char c='a'+i;
		if(cnt.count(c)==0) {
			rep(j,1,n-len)	ans+=c;
			break;
		}
	}
	cout<<ans<<endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
//	freopen("1.in", "r", stdin);
	int _;
	cin>>_;
	while(_--)
		solve();
	return 0;
}

总结

有判定正确性的思路,但是不会构造
wa了几发。最开始是构造的思路是错的
后面有一个小细节处理的不好,当要修改 s t r i n g string string时,就不能用 s t r i n g string string s i z e size size作为循环的控制条件,这样很容易寄。
很好的一道构造题目


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值