SP7155 CF25E - Test
双倍经验:CF25E
前置知识:kmp,可左转 P3375
题意即求最短的使 \(s1,s2,s3\) 均为其子串的字符串 \(s\)
很明显,字符串长度最大值就是三子串长度之和
然后考虑重合情况
化归:考虑两个子串,再考虑三个子串的情况
不妨先求最短的使 \(s1,s2\) 均为其子串的字符串 \(ss\)
两个子串仅有 \(3\) 种情况:(不妨假设 \(s1\) 的长度大于等于 \(s2\),这里顺便借用一下两圆的关系)
-
相离,例如 \(abccd\) 和 \(bddc\),此时 \(s=s1+s2\)
-
相交,例如 \(abccd\) 和 \(bccde\),此时 \(s=s1+s2-s1\cap s2\)
-
包含,例如 \(abccd\) 和 \(bcc\),此时 \(s=s1\)
其中 \(s1\cap s2\) 拿 kmp 乱搞一下就行了,求匹配结束后 \(s2\) 的指针所在位置
三个子串怎么办?
可以先求 \(ss\),再求最短的使 \(ss,s3\) 均为其子串的字符串,然后将 \(s2,s3\) 互换,重来,再将 \(s1,s3\) 互换,再来一次
也可以分多类讨论,也不难
最后献上分类讨论的代码:
#include<bits/stdc++.h>
#define inl inline
#define rep(i,a,b) for(int i=(a),i##end=(b);i<=i##end;i++)
#define pre(i,a,b) for(int i=(a),i##end=(b);i>=i##end;i--)
using namespace std;
const int N=1e6+10;
int pmt[N][4];//pmt 数组,就可以看做是整体前移的 next 数组
void get_pmt(const string &s,int t){
for(int i=1,j=0;i<s.size();++i){
while(j&&s[i]!=s[j])j=pmt[j-1][t];
if(s[i]==s[j])j++;
pmt[i][t]=j;
}
}
int kmp(string s,string p,int t1,int t2){
// if(s.size()<p.size()){swap(s,p);swap(t1,t2);}
int j=0;
for(int i=0;i<s.size();i++){
while(j&&s[i]!=p[j])j=pmt[j-1][t2];
if(s[i]==p[j])j++;
if(j==p.size())return -1;
}
return j;
}
string s[4];
int km[4][4];
signed main(void){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while(cin>>s[1]>>s[2]>>s[3]){
get_pmt(s[1],1);get_pmt(s[2],2);get_pmt(s[3],3);
km[1][2]=kmp(s[1],s[2],1,2);
km[2][1]=kmp(s[2],s[1],2,1);
km[1][3]=kmp(s[1],s[3],1,3);
km[3][1]=kmp(s[3],s[1],3,1);
km[2][3]=kmp(s[2],s[3],2,3);
km[3][2]=kmp(s[3],s[2],3,2);//这里注意:km[a][b]!=km[b][a],因为 km 第一维表示“文本串”,第二维则是“模式串”
int ans=0x3f3f3f3f;
rep(i,1,3)rep(j,1,3)rep(k,1,3){
if(i==j||j==k||i==k)continue; //只有两两不同才有意义
int sum=s[i].size()+s[j].size()+s[k].size()-km[i][j]-km[j][k]; //这里说下分多类讨论的写法
if(km[i][j]>=0&&km[j][k]>=0)ans=min(ans,sum); //如果不存在包含关系,那么 sum 即为所求
else{
if(km[i][j]<0&&km[i][k]<0)ans=min(ans,(int)s[i].size()); //存在一个大串使得其他两个小串均为其子串,那么大串长度即为所求
else if(km[i][j]<0)ans=min(ans,sum+km[i][j]+km[j][k]-(int)s[j].size()-km[i][k]);//sj 是 si 子串,那么不考虑 sj,化为两子串的问题
if(km[j][k]<0)ans=min(ans,sum+km[j][k]-(int)s[k].size()); //sk 是 sj 子串,那么不考虑 sk,化为两子串的问题
}
}
cout<<ans<<'\n';
}
}
本文来自博客园,作者:{Chthologist7507},转载请注明原文链接:https://www.cnblogs.com/Chthologist7507/articles/16777258.html

浙公网安备 33010602011771号