poj3080 Blue Jeans(KMP 枚举 | KMP 二分)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_43408238/article/details/102678853

题意是在给定的所有字符串中寻找一个最长子串且这个长度大于3,有相同长度的输出字典序最小的子串。

思路:枚举第一个子串的所有大于3的子串,在带入其他字符串中用KMP匹配。

400+ms

AC Code:

#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<sstream>
#include<algorithm>

using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define sRead(x,y,z)  scanf("%d%d%d",&x,&y,&z)
#define gc(x)  scanf(" %c",&x);
#define mmt(x,y)  memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod  998244353
#define pdd pair<double,double>
const int N = 1000;
const int M=  1e6;
int Next[1000];
string s[15];
set<string> st;
void kmp_pre(string x)
{
    int m = x.size();
    int i = 0,j = Next[0] = -1;
    while(i < m){
        while(j != -1&& x[i]!=x[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
bool  kmp(string s1,string s2){
    int n = s1.size(),m = s2.size();
    int i = 0,j = 0;
    while(i < n){
        while(j!=-1&&s1[i]!=s2[j]) j = Next[j];
        ++i,++j;
        if(j >= m)  return 1;
    }
    return 0;
}
bool solve(string tmp,int k){
    int i ;
    mmt(Next,0);
    kmp_pre(tmp);
    for( i = 2;i <= k;++i){

        if(!kmp(s[i],tmp)) break;
    }
    if(i > k) return 1;
    else return 0;
}
int main()
{
    //freopen("input.txt","r",stdin);
    int  T;
    read(T);
    while(T--){
        int k;
        st.clear();
        read(k);
        for(int i = 1;i <= k;++i){
            cin>>s[i];
        }
        int MAX = -1;
        for(int i = 0;i < s[1].size() - 3;++i){
            for(int j = s[1].size();j >=3;--j){
                if(i + j >s[1].size() ) continue;//这儿多加了一个 = ,坑死我了,逻辑错误,最为致命
                string tmp = s[1].substr(i,j);
                if(solve(tmp,k)) {
                    if(j > MAX) {MAX = j;st.clear();st.insert(tmp);}
                    else if(j == MAX) st.insert(tmp);//忘了考虑相同的情况,逻辑错误最为致命
                }
            }
        }
        if(MAX==-1) puts("no significant commonalities");
        else {
            cout<<*st.begin()<<endl;
        }
    }
}

KMP + 二分

70+ms

其实可以发现我们枚举子串长度与答案之间满足某种 单调性,即存在某种长度的子串满足题目要求,那么这个子串的子串肯定也满足,所以我们可以二分长度来加速枚举的过程,最后需要注意的是,当l + 1 > r跳出时,并没有检验长度为 l 的串,所以最后需要检验一下 l 长度的子串。

AC Code:

#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<sstream>
#include<algorithm>

using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define sRead(x,y,z)  scanf("%d%d%d",&x,&y,&z)
#define gc(x)  scanf(" %c",&x);
#define mmt(x,y)  memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define INF 0x3f3f3f3f
#define ll long long
#define mod  998244353
#define pdd pair<double,double>
const int N = 1000;
const int M=  1e6;
int Next[1000];
string s[15];
set<string> st;
void kmp_pre(string x)
{
    int m = x.size();
    int i = 0,j = Next[0] = -1;
    while(i < m){
        while(j != -1&& x[i]!=x[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
bool  kmp(string s1,string s2){
    int n = s1.size(),m = s2.size();
    int i = 0,j = 0;
    while(i < n){
        while(j!=-1&&s1[i]!=s2[j]) j = Next[j];
        ++i,++j;
        if(j >= m)  return 1;
    }
    return 0;
}
bool solve(string tmp,int k){
    int i ;
    mmt(Next,0);
    kmp_pre(tmp);
    for( i = 2;i <= k;++i){

        if(!kmp(s[i],tmp)) break;
    }
    if(i > k) return 1;
    else return 0;
}
int MAX = -1;
bool ok(int l,int k){
    bool r = 1;
    for(int i = 0;i < s[1].size();++i){
        if(l + i > s[1].size()) continue;
        string tmp = s[1].substr(i,l);
        if(solve(tmp,k)) {
             if(l > MAX) MAX = l,st.clear();
             st.insert(tmp);
             r = 0;
        }
    }
    return r == 1?0:1;
}
int main()
{
   // freopen("input.txt","r",stdin);
    int  T;
    read(T);
    while(T--){
        int k;
        st.clear();
        read(k);
        for(int i = 1;i <= k;++i){
            cin>>s[i];
        }
        int l = 3,r = s[1].size();
        MAX = -1;
        while(l < r){
            int mid = l + r >> 1;
            if(ok(mid,k)) l = mid + 1;
            else r = mid;
        }
        ok(l,k);//检验 长度为l 的子串
        if(st.size()==0) puts("no significant commonalities");
        else {
            cout<<*st.begin()<<endl;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43408238/article/details/102678853
今日推荐