P9523 [JOISC 2022] 复制粘贴 3 题解

Description

JOI 公司是一家以“没啥用发明”而闻名的公司。最近,JOI 公司开发了一款名为“没啥用编辑器”的编辑器。

在这个编辑器中,可以执行如下几种操作来输入某个字符串,设 XX 为屏幕上的字符串,YY 为剪切板中的字符串,初始均为空串:

  • 操作 A:输入字符 cc,即将 XX 更新为 X+cX+c
  • 操作 B:选择所有字符并剪切,即将 YY 更新为 XX,并将 XX 置为空串。
  • 操作 C:将剪切板中的字符串粘贴到当前字符串末尾,即将 XX 更新为 X+YX+Y

对于字符串或字符 x,yx,yx+yx+y 表示将 xxyy 顺次拼接得到的结果。使用一次操作 A,B,C 分别要花费 A,B,CA,B,C 单位时间。

你安装了“没啥用编辑器”,并想要尽可能快地输入一个长度为 NN 的字符串 SS

你需要计算出最少需要花费多少时间。

  • 1N25001\leq N\leq 2500
  • SS 是一个长度为 NN 的小写字母串。
  • 1A,B,C1091\leq A,B,C\leq 10^9

Solution

考虑设 fl,rf_{l,r} 表示目前屏幕上为 Sl,rS_{l,r} 的最小代价。

首先有转移:fl,rmin{fl,r1+A,fl+1,r+A}f_{l,r}\leftarrow\min\{f_{l,r-1}+A,f_{l+1,r}+A\}

然后就可以钦定下一步一定是把 Sl,rS_{l,r} 放进剪切板,然后复制粘贴 kk 次。

这里继续钦定复制粘贴时一定以 ll 为左端点,即到下一次 B 操作时,状态为 [l,p][l,p],且 [l,p][l,p] 中包含至少 kk 个不相交的 Sl,rS_{l,r}

考虑枚举 kk,转化为找到最小 pp 满足 [l,p][l,p] 包含 kk 个互不相交的 [l,r][l,r],预处理出 nxtl,rnxt_{l,r} 表示 rr 右边第一个与 Sl,rS_{l,r} 相等的子串的右端点即可。转移如下:fl,pfl,r+B+Ck+A(pl+1k(rl+1))\displaystyle f_{l,p}\leftarrow f_{l,r}+B+C\cdot k+A\cdot \left(p-l+1-k\cdot (r-l+1)\right)

下面证明一下为什么第一次复制粘贴一定以 ll 为左端点。

归纳证明,先假设长度小于等于 rl+1r-l+1 的都满足了条件,那么容易发现对于任意一个 [pl,pr][pl,pr],如果满足 [pl,pr][pl,pr] 内包含至少 kkSl,rS_{l,r} 且从中删掉左右端点都不满足条件的话,一定存在另一个和 Sl,rS_{l,r} 相等的串以 plpl 为左端点,否则左端点就可以加一。这也就说明了转移一定不会少东西。

时间复杂度:O(n2lnn)O(n^2\ln n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>

// #define int int64_t

using i64 = int64_t;
using u64 = uint64_t;

const int kMaxN = 2505;

int n;
int nxt[kMaxN][kMaxN];
i64 A, B, C, f[kMaxN][kMaxN];
u64 hs[kMaxN], pw[kMaxN];
std::string str;

u64 gethash(int l, int r) { return hs[r] - hs[l - 1] * pw[r - l + 1]; }

void prework() {
pw[0] = 1;
for (int i = 1; i <= n; ++i) {
pw[i] = 13331ull * pw[i - 1];
hs[i] = 13331ull * hs[i - 1] + str[i];
}
}

void getnxt() {
std::unordered_map<u64, int> mp;
for (int i = n; i; --i) {
for (int j = i; j; --j) {
u64 hsh = gethash(j, i);
if (mp.count(hsh)) nxt[j][i] = mp[hsh];
}
for (int j = i; j <= n; ++j) mp[gethash(i, j)] = j;
}
}

void dickdreamer() {
std::cin >> n >> str >> A >> B >> C;
str = " " + str;
prework(), getnxt();
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= n + 1; ++i) f[i][i - 1] = 0;
for (int len = 1; len <= n; ++len) {
for (int i = 1; i <= n - len + 1; ++i) {
int j = i + len - 1;
f[i][j] = std::min({f[i][j], f[i + 1][j] + A, f[i][j - 1] + A});
for (int k = 1, p = j; p; ++k, p = nxt[p - len + 1][p]) {
f[i][p] = std::min(f[i][p], f[i][j] + B + C * k + A * (p - i + 1 - k * len));
}
}
}
std::cout << f[1][n] << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P9523 [JOISC 2022] 复制粘贴 3 题解
https://sobaliuziao.github.io/2025/04/02/post/e1b46dff.html
作者
Egg_laying_master
发布于
2025年4月2日
许可协议