专栏文章
CF1789F题解
CF1789F题解参与者 4已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @minsbc9x
- 此快照首次捕获于
- 2025/12/02 07:32 3 个月前
- 此快照最后确认于
- 2025/12/02 07:32 3 个月前
一道人类智慧题
题意简要
称一个字符串 是好的,当且仅当存在字符串 和正整数 ,使得 可以通过 个 首尾拼接得到。给定字符串 ,求他最长的好的子序列。(不要求连续)
正文
考虑枚举 ,拼凑两个暴力:
- 将 划分成 个部分,对于每个部分求 ,复杂度 ( 是假的),能跑过 。
- 将 划分成长度为 的串,则 一定是某个部分的子串。
所以我们考虑求每个部分的子串,贪心匹配求答案即可。复杂度 ,能跑过 ,而在写代码中你只用考虑 时(可以自己想想为什么)
证明
考虑反证法。如果不是子序列,则说明跨度 。又因为有 段,所以跨度 ,矛盾。
那 时,怎么办呢?显然,答案字符串 ,在 时算过,所以不用管,然后就做完了。
code
CPP#include <bits/stdc++.h>
using namespace std;
string s;
int n, m, f[81][81], f2[81][81][81], ans;
int LSC1(string &s, string &t){//求两个字符串的LCS,传引用更快
memset(f, 0, sizeof f);//清空
int l1 = s.size(), l2 = t.size();
s = ' ' + s, t = ' ' + t;//转移下标
for(int i = 1; i <= l1; i++){
for(int j = 1; j <= l2; j++){
if(s[i] == t[j])
f[i][j] = f[i - 1][j - 1] + 1;
f[i][j] = max({f[i][j], f[i - 1][j], f[i][j - 1]});
}
}//普通的nm求解
return f[l1][l2];
}
int LSC2(string &s, string &t, string &r){//求三个字符串的LCS,传引用更快
memset(f2, 0, sizeof f2);//清空
int l1 = s.size(), l2 = t.size(), l3 = r.size();
s = ' ' + s, t = ' ' + t, r = ' ' + r;//转移下标
for(int i = 1; i <= l1; i++){
for(int j = 1; j <= l2; j++){
for(int k = 1; k <= l3; k++){
if(s[i] == t[j] && t[j] == r[k])
f2[i][j][k] = f2[i - 1][j - 1][k - 1] + 1;
f2[i][j][k] = max({f2[i][j][k], f2[i - 1][j][k], f2[i][j - 1][k], f2[i][j][k - 1]});
}
}
}
return f2[l1][l2][l3];
}
string t, s1;//枚举s1的子串t
void dfs(int x){
if(x == s1.size()){
int p = 0, sz = t.size(), cnt = 0;
if(sz > 0){
for(char c : s){
if(c == t[p]){
cnt += p == sz - 1;
p = (p + 1) % sz;
}
}
}//贪心匹配
if(cnt < 2) cnt = 0;//必须至少出现两次
ans = max(ans, sz * cnt);
return ;
}
dfs(x + 1);
t.push_back(s1[x]);
dfs(x + 1);
t.pop_back();
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> s;
n = s.size();
for(int i = 0; i < n; i++){
string t1 = s.substr(0, i), t2 = s.substr(i);
ans = max(ans, 2 * LSC1(t1, t2));
}
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
string t1 = s.substr(0, i), t2 = s.substr(i, j - i), t3 = s.substr(j);
ans = max(ans, 3 * LSC2(t1, t2, t3));
}
}
int m = (n + 4) / 5;//一定得向上取整,不然会WA最后一个点,有点玄学
for(int i = 0; i < n; i += m){
s1 = s.substr(i, m);
dfs(0);
}
cout << ans;
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...