原题题面
题目描述
构造一个字符串 。
对于该处的字符串给出 个限制,每个限制给出一个 和一个 ,意为前 个字符组成的子串有 个回文子串。
共有 组样例。
输入输出格式
输入样例
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
题目分析
首先,我们可以证明对于“本质不同的回文子串”的数量,每个位置 对于整体的数量最多只有 的贡献。
具体证明见 pzr的知乎题解。
那么,对于每次向后的拓展,若 ,则意味着无法构造出符合要求的数列。
然后,我们注意到 的限制不大于 ,这是一个很重要的提示,先打个标记。
若后续拓展新得到的贡献为 ,我们可以选择一个并未用过的字母,直接将 个相应字母填到数列的后面,由于之前的证明,我们可以知道每个字母对总体的贡献有且仅为 。
而对于无贡献的拓展部分,我们可以以 进行循环输出。这里需要注意两点,其一最开始的数列长度大于等于 ,我们可以一开始将初始数组定为 ,然后按序进行拓展。其二,在两个相邻拓展的 循环拆开拼合后必须连续,否则会出现 这种出现新贡献的错误。
具体解法见代码。
Accept代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t; cin >> t;
while (t --)
{
int n, k; cin >> n >> k;
vector<int> x(k + 1), c(k + 1);
bool flg = true;
for (int i = 1; i <= k; i ++) cin >> x[i];
for (int i = 1; i <= k; i ++)
{
cin >> c[i];
if (c[i] - c[i - 1] > x[i] - x[i - 1]) flg = false;
}
if (!flg)
{
cout << "NO" << "\n";
continue;
}
int u = 3;
cout << "YES\nabc";
int m = 0;
string sf = "abc";
for (int i = 1; i <= k; i ++)
{
int xf = x[i] - x[i - 1];
int cf = c[i] - c[i - 1];
if (i == 1) xf -= 3, cf -= 3;
for (int j = 0; j < cf; j ++) cout << (char)('a' + u);
u ++;
for (int j = cf; j < xf; j ++)
{
cout << sf[m];
m = (m + 1) % 3;
}
}
for (int i = x[k]; i < n; i ++) cout << 'a';
cout << "\n";
}
return 0;
}