|
| 1 | +/* |
| 2 | +APIO 2011 Guess My Word |
| 3 | +- A state in this game consists of the following info: |
| 4 | + - The set of candidate words (cand) |
| 5 | + - The set of positions whose letters are already known (mask) |
| 6 | + - The number of remaining wrong guesses (rem) |
| 7 | +- If |cand| == 0 (i.e. A contradicted themselves), then B wins |
| 8 | +- Otherwise, if rem == 0 (i.e. B made too many wrong guesses), |
| 9 | + then A wins |
| 10 | +- Otherwise, if |cand| == 1 (i.e. B narrowed the set of words |
| 11 | + down to a single one), then B wins |
| 12 | +- Otherwise, the following happens: |
| 13 | + - B must guess a letter present in one of the candidates |
| 14 | + in a position whose letter is still unknown |
| 15 | + - A then chooses whether to confirm the letter and in which |
| 16 | + position, or to tell B that their guess was wrong |
| 17 | + - If A is able to force a win by using *any* such move |
| 18 | + *for all* possible letters that B guesses, then A wins; |
| 19 | + otherwise, B wins |
| 20 | +- No idea what the complexity is, but it's fast enough |
| 21 | +*/ |
| 22 | + |
| 23 | +#include <bits/stdc++.h> |
| 24 | +typedef long long ll; |
| 25 | +using namespace std; |
| 26 | + |
| 27 | +string s[1000]; |
| 28 | +vector<int> has_len[8]; |
| 29 | + |
| 30 | +bool possible(int len, vector<int> cand, int mask, int rem) { |
| 31 | + if (!cand.size()) return false; |
| 32 | + if (!rem) return true; |
| 33 | + if (cand.size() == 1) return false; |
| 34 | + |
| 35 | + bool good[26]; |
| 36 | + memset(good, 0, sizeof good); |
| 37 | + for (int i = 0; i < len; i++) if (!(mask & (1 << i))) { |
| 38 | + for (int j : cand) good[s[j][i] - 'A'] = true; |
| 39 | + } |
| 40 | + |
| 41 | + bool all = true; |
| 42 | + for (char i = 'A'; i <= 'Z'; i++) if (good[i - 'A']) { |
| 43 | + vector<vector<int>> match(len); |
| 44 | + vector<int> nomatch; |
| 45 | + for (int j : cand) { |
| 46 | + bool found = false; |
| 47 | + for (int k = 0; k < len && !found; k++) if (s[j][k] == i) { |
| 48 | + match[k].push_back(j); |
| 49 | + found = true; |
| 50 | + } |
| 51 | + if (!found) nomatch.push_back(j); |
| 52 | + } |
| 53 | + bool any = possible(len, nomatch, mask, rem - 1); |
| 54 | + for (int j = 0; j < len && !any; j++) if (!(mask & (1 << j))) |
| 55 | + any = possible(len, match[j], mask + (1 << j), rem); |
| 56 | + all &= any; |
| 57 | + } |
| 58 | + return all; |
| 59 | +} |
| 60 | + |
| 61 | +int main() { |
| 62 | + cin.tie(0)->sync_with_stdio(0); |
| 63 | + int t; |
| 64 | + cin >> t; |
| 65 | + while (t--) { |
| 66 | + int n; |
| 67 | + cin >> n; |
| 68 | + for (int i = 0; i < n; i++) { |
| 69 | + cin >> s[i]; |
| 70 | + has_len[s[i].size()].push_back(i); |
| 71 | + } |
| 72 | + bool any = false; |
| 73 | + for (int i = 1; i <= 7; i++) { |
| 74 | + if (!any) any = possible(i, has_len[i], 0, i + 1); |
| 75 | + has_len[i].clear(); |
| 76 | + } |
| 77 | + cout << (any ? "Yes" : "No") << '\n'; |
| 78 | + } |
| 79 | + return 0; |
| 80 | +} |
0 commit comments