专栏文章

题解:P12124 [蓝桥杯 2024 省 B 第二场] 前缀总分

P12124题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miod15py
此快照首次捕获于
2025/12/02 17:12
3 个月前
此快照最后确认于
2025/12/02 17:12
3 个月前
查看原文

题意简述

给定 nn 个字符串 s1ns_{1 \sim n} ,修改某字符串的某个字符,使 i<jLCP(si,sj)\sum_{i<j} \operatorname{LCP}(s_i,s_j) 最大。LCP(p,q)\operatorname{LCP}(p, q) 为字符串 p,qp, q 的最长公共前缀长度。

思路

考虑 dp。定义 fi,j,kf_{i, j, k} 表示 sis_isjs_j 从第 kk 位开始到结尾的子串的最长公共前缀长度。
状态转移:
fi,j,k={0,si,ksj,kfi,j,k+1+1,si,k=sj,kf_{i, j, k} = \begin{cases} 0, & s_{i, k} \neq s_{j, k}\\ f_{i, j, k+1} + 1, & s_{i, k} = s_{j, k} \end{cases}
统计答案时,我们枚举要修改的字符串编号 ii,修改字符的下标 kk 和修改后的字符 cc。记这次修改可以使答案增加 dd。对于所有 jij \neq i,有以下两种情况使答案变动:
  • 如果 fi,j,1=k1f_{i, j, 1} = k-1c=sj,kc = s_{j,k},这说明原本 sis_isjs_j 相等的部分在第 kk 位这里断开了,修改之后可以给它接上。dd+fi,j,k+1+1d \gets d + f_{i,j,k+1}+1
  • 如果 fi,j,1kf_{i,j,1} \ge kcsj,kc \neq s_{j,k},这说明原本 sis_isjs_j 有一个较长的最长公共前缀,我们这次修改给它破坏了。dd(fi,j,1k+1)d \gets d - (f_{i,j,1}-k+1)
记原本不加修改的答案为 ansans。则 ans+max{d}ans + \max\{d\} 即为最终答案。时间复杂度 O(n2si)\mathcal O(n^2|s_i||\sum|),其中 =26|\sum| = 26

代码

CPP
#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;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...