1. 程式人生 > 其它 >【字串 暴力】Word

【字串 暴力】Word

暴力

題面

有k個字串{S1,S2,…,Sk},其中的每個字元不是空格,就是26個小寫英文字母中的一個。對於常數 l和d,我們的目標是從這k個字串中得出一個(l,d)-樣詞,它是一個長度為l的字串W=W[1]W[2]...W[l],它的每個字元必須符合下面的條件:
每個字串Si(i=1,2,…,k)都有一個長度為l的子串X=X[1]X[2]...X[l],X和W的出錯率小於或等於d。(X和W的出錯率是(X[j],W[j])的對數,其中,X[j]<>W[j],j=1,2,…,l)
在這個任務中,給你 l,d和一組字串;你要從中得出一個(l,d)-樣詞。你可以預設(l,d)-樣詞是存在的,而且是唯一的。
例1
如下3個字串,相對應的(3,0)-樣詞是“oil”:
oil is expensive
we have three oilers
be more oily

例2
如下4個字串,相對應的(5,1)-樣詞是“apple”:
you have two applas
i am an ppple
we are acples
adples are good for health

思路

分析一下暴力演算法的時間複雜度,會爆炸。
但是跑不滿。

程式碼

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast")
#include <cstdio>
#include <cstring>
#include <iostream>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)

int l, d, k;
int len[31];
char s[31][51], tmp[51];
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

struct Trie {
	int trie[1501][28], cnt;
	void insert(int rt, int l, int r) {
		int p = 0, tmp;
		for (int i = l; i <= r; i++) {
			if (s[rt][i] != ' ')
				tmp = s[rt][i] - 96;
			else
				tmp = 27;
			if (!trie[p][tmp])
				trie[p][tmp] = ++cnt;
			p = trie[p][tmp];
		}
	}
	int check(int dep, int p, int sum) {
		if (sum > d)
			return 0;
		if (dep == l)
			return 1;
		int now, res = 0;
		if (tmp[dep] == ' ')
			now = 27;
		else
			now = tmp[dep] - 96;
		for (int i = 1; i <= 27; i++)
			if (trie[p][i])
				res |= check(dep + 1, trie[p][i], sum + 1 - (i == now));
		return res;
	}
} tree[31];

inline bool isok (char ch) {
	return isalpha(ch) || ch == ' ';
}

int reads (char *s) {
	char ch = getchar();
	int p = -1;
	while (!isok(ch)) ch = getchar();
	while (isok(ch)) s[++p] = ch, ch = getchar();
	s[++p] = 0;
	return p;
}

int main() {
	scanf("%d %d %d\n", &l, &d, &k);
	int mm = 1;
	for (int i = 1; i <= k; i++) {
		len[i] = reads(s[i]);
		if (len[i] < len[mm])
			mm = i;
	}
	std::swap(s[mm], s[1]);
	std::swap(len[mm], len[1]);
	for (int i = 2; i <= k; i++)
		for (int j = 0; j < len[i] - l + 1; j++)
			tree[i].insert(i, j, j + l - 1);
	int flag, tmpf;
	for (int i = 0; i < len[1] - l + 1; i++) {
		int L = i, R = i + l - 1;
		flag = 0;
		for (int j = L; j <= R; j++)
			tmp[j - L] = s[1][j];
		if (d == 1) {
			for (int a = 0; a < l; a++)
				for (int sa = 1; sa <= 27; sa++) {
					char ch = tmp[a];
					if (sa == 27)
						tmp[a] = ' ';
					else
						tmp[a] = (char)sa + 96;
					tmpf = 1;
					for (int j = 2; j <= k; j++)
						if (!tree[j].check(0, 0, 0)) {
							tmpf = 0;
							break;
						}
					flag |= tmpf;
					if (flag)
						return !printf("%s", tmp);
					tmp[a] = ch;
				}
		} else if (d == 2) {
			for (int a = 0; a < l; a++)
				for (int b = a + 1; b < l; b++)
					for (int sa = 1; sa <= 27; sa++)
						for (int sb = 1; sb <= 27; sb++) {
							char cha = tmp[a], chb = tmp[b];
							if (sa == 27)
								tmp[a] = ' ';
							else
								tmp[a] = (char)sa + 96;
							if (sb == 27)
								tmp[b] = ' ';
							else
								tmp[b] = (char)sb + 96;
							tmpf = 1;
							for (int j = 2; j <= k; j++)
								if (!tree[j].check(0, 0, 0)) {
									tmpf = 0;
									break;
								}
							flag |= tmpf;
							if (flag)
								return !printf("%s", tmp);
							tmp[a] = cha, tmp[b] = chb;
						}
		} else {
			flag = 1;
			for (int j = 2; j <= k; j++)
				if (!tree[j].check(0, 0, 0)) {
					flag = 0;
					break;
				}
			if (flag)
				return !printf("%s", tmp);
		}
	}
}

讀入用scanf或getchar比較穩