题解:P12124 [蓝桥杯 2024 省 B 第二场] 前缀总分
题意简述
给定
思路
考虑 dp。定义
状态转移:
统计答案时,我们枚举要修改的字符串编号
-
如果
f_{i, j, 1} = k-1 且c = s_{j,k} ,这说明原本s_i 和s_j 相等的部分在第k 位这里断开了,修改之后可以给它接上。d \gets d + f_{i,j,k+1}+1 。 -
如果
f_{i,j,1} \ge k 且c \neq s_{j,k} ,这说明原本s_i 和s_j 有一个较长的最长公共前缀,我们这次修改给它破坏了。d \gets d - (f_{i,j,1}-k+1) 。
记原本不加修改的答案为
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 205;
string s[N];
int f[N][N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s[i];
s[i] = " " + s[i];
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = min(s[i].size(), s[j].size())-1; k >= 1; k--)
if (s[i][k] == s[j][k])
f[i][j][k] = f[i][j][k+1] + 1;
int ans0 = 0;
for (int i = 1; i <= n; i++)
for (int j = i+1; j <= n; j++)
ans0 += f[i][j][1];
int ans = ans0;
for (int i = 1; i <= n; i++) {
for (int k = 1; k < s[i].size(); k++) {
for (char c = 'a'; c <= 'z'; c++) {
int add = 0;
for (int j = 1; j <= n; j++) {
if (j == i || k >= s[j].size()) continue;
if (f[i][j][1] == k-1 && c == s[j][k])
add += f[i][j][k+1]+1;
if (f[i][j][1] >= k && c != s[j][k])
add -= f[i][j][1]-k+1;
}
ans = max(ans, ans0+add);
}
}
}
cout << ans << endl;
return 0;
}