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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章