SPOJ CF25E(KMP)

题目链接

这题搞的我真的是快崩溃了,题意说的有点不清楚,有可能是我太蠢,没注意到是子串就不用再加一串的情况,2个小时的kmp,纪念一下8。

题意:
给你三个字符串a,b,c, 现在让你构造一个字符串,条件是这个字符串中能找到a,b,c这三个子串(这个子串是要连续的),现在问你构造的最短长度是多少。

思路:
一开始想的是假如a后面是b,那么就要求一下a的后缀和b的前缀的公共部分,用same[i][j]来表示这个公共部分的长度,然后我就搞了一下(b+a)这个串的next数组,公共部分就是next[len(a+b)](真的nt),其实可以用kmp求,最后如果匹配到了,就直接return那个模式串的长度,没匹配到最后就return最后匹配到的模式串的下标,也就是模式串的前缀和主串的后缀匹配的长度。

接下来就三个for枚举a,b,c依次连起来所需的长度,有个情况要注意一下,b是a的子串,并且c也是a的子串,那就要单独拿出来考虑,所需长度就是len[a],(罚时+1h)。剩下的情况
1.b是a的子串,那么因为c肯定不是a的子串咯,而且现在c要连在a后面,所以+len[a]+len[c]-same[a][c]。
2.c是a的子串,那么因为b不是a的子串,所以+len[a]+len[b]-same[a][b]。
3.没有子串关系,所以+len[a]+len[b]+len[c]-same[a][b]-same[b][c]。

#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 2*(int)1e5+1000;
char s[3][maxn], x[maxn];
int len[3], nxt[maxn], same[3][3];

void kmp_pre(char x[], int m, int nxt[]) {
	int i, j;
	j = nxt[0] = -1;
	i = 0;
	while (i <= m) {
		while (-1 != j && x[i] != x[j]) j = nxt[j];
		nxt[++i] = ++j;
	}
}
int kmp_count(char x[], int m, char y[], int n) {
	int i, j;
	int ans = 0;
	kmp_pre(x, m, nxt);
	i = j = 0;
	while (i < n) {
		while (-1 != j && y[i] != x[j]) j = nxt[j];
		++i;
		++j;
		if (j >= m) {
			return m;
			++ans;
			j = nxt[j];
		}
	}
	return j;
}

int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

	while (cin >> s[0] && cin >> s[1] && cin >> s[2]) {
        for (int i = 0; i < 3; ++i) len[i] = strlen(s[i]);
		for (int i = 0; i < 3; ++i) {
			for (int j = 0; j < 3; ++j) {
				if (i == j) continue;
				int temp = kmp_count(s[j], len[j], s[i], len[i]);
				same[i][j] = temp;
			}
		}
		int ans = INT_MAX;
		for (int i = 0; i < 3; ++i) {
			for (int j = 0; j < 3; ++j) {
				if (j == i) continue;
				for (int k = 0; k < 3; ++k) {
					if (k == j || k == i) continue;
					if (same[i][j] == len[j] && same[i][k] == len[k]) ans = min(ans, len[i]);
					else if (same[i][j] == len[j]) ans = min(ans, len[i]+len[k]-same[i][k]);
					else if (same[j][k] == len[k]) ans = min(ans, len[i]+len[j]-same[i][j]);
					else {
						ans = min(ans, len[i]+len[j]+len[k]-same[i][j]-same[j][k]);
					}
				}
			}
		}
		cout << ans << '\n';
	}

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值