P9087 「SvR-2」音符

· · 题解

P9087 「SvR-2」音符

题意

构造题目。定义 \text{XX}两个连续的相同字符

有两种代价:

构造一个字符串使得总代价最小。

Solution

考虑 \text{XX} 的影响:造成 a 的代价;在不越界的情况下可以被 k-1 个子串所包含,消除 (k-1)\times{b} 的代价。

特判 k=2 的情况,此时发现字符串只有可能为全是相同字符的字符串或不存在 \text{XX} 的字符串。因为如果是两个混合的话,贡献为 c_1\times{a}+c_2\times{b},[c_1+c_2=n-1],显然不如 (n-1)\times\min(a,b) 更优。

根据上面的分析:可以不使用 \text{XX} 的判断依据是:

{a}\geqslant{b}\times(k-1)

此时直接随意输出一个不存在 \text{XX} 的字符串即可,贡献为 b\times(n-k+1)

否则构造含有 \text{XX} 的字符串:

![](https://cdn.luogu.com.cn/upload/image_hosting/lfcn4nvm.png) 当 $l,r\in[1,n]$ 时,在 $m,m-1$ 的位置放置 $\text{XX}$,即 ${a}\times{cnt}$。 当 ${r}\gt{n}$ 时,继续在 $m,m-1$ 的位置放置 $\text{XX}$ 或者计算 $n-m+1$ 个剩余字串的代价,即 $\min\{a,b\times(n-m+1)\}$。 ## Example 如果不能理解的话,举个例子。假设 $n=15,k=5$。 观察一个 $\text{XX}$ (红色部分 $[4,5]$)在**不越界**时可以影响的 $k-1$ 个子串(蓝色部分 $[1,8]$): ![](https://cdn.luogu.com.cn/upload/image_hosting/uxq5n45f.png) 发现 $[5,9]$ 这个子串的 $b$ 的代价无法被 $[4,5]$ 消除。若要继续消除 $b$ ,需要每隔 $k-1$ 个位置再放置一个 $\text{XX}$。 ![](https://cdn.luogu.com.cn/upload/image_hosting/0mnguqrb.png) 按照上面的构造方案,若在 $[12,13]$ 放一个 $\text{XX}$ 会溢出 $[16,16]$,这样可能会浪费。此时便有两种选择:继续花费 $a$ 的代价放置 $\text{XX}$ 或者直接计算剩余子串 $b$ 的代价。 此时剩余无法覆盖的子串(图中黄线)的数量为 $n-m+1$ 个,花费 $a$ 的代价放置 $\text{XX}$ (图中红虚线)或者花费 $b\times(n-m+1)$ 的代价,两者取代价最小的。 ![](https://cdn.luogu.com.cn/upload/image_hosting/v57499to.png) ![](https://cdn.luogu.com.cn/upload/image_hosting/8mmaxh4i.png) ## Code ```cpp #include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e5 + 5; char s[N]; char name[10] = "Nahida"; /*随机定义一个不含有 XX 的字符串即可*/ char same[10] = "AC"; /*选择两个字符是因为 k=3 时这种构造方案会出现 XXXX 的情况,改为 XXYY 即可*/ int T, n, k, a, b; signed main() { cin >> T; while (T --> 0) { int ans = 0, cnt = 0, m = 0; cin >> n >> k >> a >> b; s[n + 1] = '\0'; for (int i = 1; i <= n; i++) s[i] = (k == 2 && a < b) ? 'Q' : name[(i - 1) % 6]; if (k == 2) {ans = (n - 1) * min(a, b);goto print;} if (a >= (k - 1) * b) {ans = b * (n - k + 1);goto print;} for (int l = 1, r; m = l + k - 1, (r = m + k - 2) <= n; l = m) s[m] = s[m - 1] = same[(++cnt) & 1]; if (a < (n - m + 1) * b) s[m] = s[m - 1] = same[(++cnt) & 1]; else ans = (n - m + 1) * b; print: cout << max(ans + a * cnt, 0ll) << '\n' << (s + 1) << '\n'; } return 0; } ```