公式

C - Fishbones 解説 by en_translator


Approach

For the \(i\)-th character of each \(S_j\), consider determining the following fast:

  • Among \(S_1, \cdots, S_M\), is there a string of length \(B_i\), and the \(A_i\)-th string coincides with \(S_j[i]\)?

It seems difficult to optimize a naive algorithm, so we will try to precalculate necessary values.

Let \(\mathrm{memo}[len][place][c]\) be the value representing whether there exists a string of length \(n\) whose \(place\)-th character is \(c\) among \(S_1, \cdots, S_M\). Initialize them with False, and perform the following preprocess:

  • For each \(i\)-th character of \(S_j\), if it equals \(c\), set \(\mathrm{memo}[|S_j|][i][c]\) to True.

This preprocess runs in \(O(N^2_{max} \sigma + N_{max}M)\) time (where \(N_{max} := \max(|S_1|, \cdots, |S_M|)\) and \(\sigma\) is the size of alphabet). Once the preprocess is done, all \(\mathrm{memo}\) contain correct values.

This enables \(O(1)\) determination for each position, for a total runtime of \(O(N^2_{max} \sigma + N_{max}M)\), which is fast enough.

Sample code (C++)

The following is sample code in C++.

Note that we assume that lowercase English letters (a-z) have consecutive character codes. Thus, while this code runs in most mainstream environment, it is not guaranteed to work as intended in your environment.

#include <iostream>
using std::cin;
using std::cout;
#include <vector>
using std::vector;
using std::pair;
using std::make_pair;
using std::min;
using std::max;
#include <string>
using std::string;

typedef long long int ll;

const int MAX_N = 10;
const int SIGMA = 26;

int n, m;
vector<int> a, b;
vector<string> s;

void solve () {
	// has[i][j][k] == 1 iff there exists s such that |s| == i, s[j] == ('a' + k)
	int has[MAX_N + 1][MAX_N][SIGMA];
	// init with 0
	for (int i = 0; i <= MAX_N; i++) {
		for (int j = 0; j < MAX_N; j++) {
			for (int k = 0; k < SIGMA; k++) {
				has[i][j][k] = 0;
			}
		}
	}
	// set 1
	for (int i = 0; i < m; i++) {
		int sz = s[i].size();
		for (int j = 0; j < sz; j++) {
			has[sz][j][s[i][j] - 'a'] = 1;
		}
	}

	vector<int> isyes(m, 0);
	// answer for each s
	for (int i = 0; i < m; i++) {
		int sz = s[i].size();
		if (sz != n) continue;

		bool isok = true;
		for (int j = 0; j < n; j++) {
			if (has[a[j]][b[j] - 1][s[i][j] - 'a'] == 0) isok = false;
		}
		if (isok) {
			isyes[i] = 1;
		}
	}

	// output
	for (int i = 0; i < m; i++) {
		cout << (isyes[i] ? "Yes" : "No") << "\n";
	}
}

int main (void) {
	std::cin.tie(nullptr);
	std::ios_base::sync_with_stdio(false);

	cin >> n;
	a.resize(n);
	b.resize(n);
	for (ll i = 0; i < n; i++) {
		cin >> a[i] >> b[i];
	}

	cin >> m;
	s.resize(m);
	for (ll i = 0; i < m; i++) {
		cin >> s[i];
	}


	solve();

	return 0;
}

投稿日時:
最終更新: