输入样例:
7
10 2
5 10
5 6
3 1
3
3
4 2
3 4
3 3
4 2
3 4
3 4
4 1
4
5
10 3
4 6 10
4 5 8
10 4
4 6 7 10
4 5 7 8
输出样例:
YES
abcbbcabcb
YES
foo
YES
ayda
YES
wada
NO
YES
abcbcacbab
NO
题意:要求构造出一个长度为n,满足k个条件的字符串。条件为字符串的前a[i]个字符组成的字符串中有b[i]个不同的回文子串。
思路:
设a为字符的个数,b为回文数的个数
1. NO的情况:多一个字符最多多构成一个回文,所以当a[i] - a[i - 1] < b[i] - b[i - 1]时,输出NO
2. 构造这个字符串的主要思想:
2.1 首先选择三个字母作为开头(题目里已经明确种类大于等于3),同时这三个字母也是接下来减少回文子串的关键,为什么不是两个字母呢?因为我们是要拿这个三个字母来减少回文子串,即这几个字符组成的串不能构成除单个字符以外的回文子串,而ababab就会构成回文子串,abcabc就不会。
2.2 每次操作都用不同的字母重复的添加在字符串里,n个重复的字母构成了n个回文子串,保证了回文子串的增加,不重复的字母保证了每次增加的回文子串都不一样。数据的条件数不超过20,加上开头用到字母3个,26个字母完全够用。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int a[N], b[N];
void solve(){
int n, k; cin >> n >> k;
for(int i = 1; i <= k; i++) cin >> a[i];
for(int i = 1; i <= k; i++) cin >> b[i];
string s = "abc", ans = "abc";
int cnt = 3, mk = 0;
a[0] = b[0] = 3;
for(int i = 1; i <= k; i++){
int x = a[i] - a[i - 1];
int y = b[i] - b[i - 1];
if(y > x){
printf("NO\n");
return ;
}
if(y){
for(int i = 0; i < y; i++) ans.push_back('a' + cnt);
cnt++;
}
for(int i = 0; i < x - y; i++){
ans.push_back(s[mk]);
mk = (mk + 1) % 3;
}
}
cout << "YES\n" << ans << "\n";
}
int main(){
// ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int tt = 1;
cin >> tt;
while(tt--){
solve();
}
}