1 条题解
-
0
思路与算法
统计每份答案字符串的频次。对候选标准串s,满分人数等于freq(s),零分人数等于freq(complement(s))。若p>0,候选只能来自已出现串;若p=0且q>0,候选只能是已出现串的互补。逐项检查并取最小。若p=q=0,从全N串开始按二进制字典序递增,寻找既未出现又不是任何已出现串互补的第一个串。
正确性说明
一份判断题答案恰好满分当且仅当与标准全部相同,恰好零分当且仅当每位相反,所以两个频次条件充分且必要,其余答案自然既非满也非零。p或q为正时有限候选来源是必要条件,全部枚举即可。两者都0时禁用串最多2n个,按字典序第一个未禁用串最优;若完整二进制空间均禁用则输出-1。
复杂度
设不同答案U≤n、题数m。使用有序map,读入与查询总时间O(nm log(U+1)),最坏寻找缺失串也至多2U+1次、同量级。空间O(Um)。字符串、频次容器初始化与互补串构造均包含,不枚举2^500个串。
易错点
N的字典序小于Y。不能只检查p个人相同而忽略互补串的q人。p=q=0时答案可能没有人在输入中给出。独立小m枚举全部标准串,大规模用频次可精确计算的互补组与最小缺失串构造。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; string opposite(string s) { for (char &c : s) c = c == 'N' ? 'Y' : 'N'; return s; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, p, q; cin >> n >> m >> p >> q; map<string, int> count; for (int i = 0; i < n; ++i) { string s; cin >> s; ++count[s]; } auto freq = [&](const string &s) { auto it = count.find(s); return it == count.end() ? 0 : it->second; }; string answer; if (p || q) { for (const auto &entry : count) { string s = p ? entry.first : opposite(entry.first); if (freq(s) == p && freq(opposite(s)) == q && (answer.empty() || s < answer)) answer = s; } } else { string s(m, 'N'); while (true) { if (!freq(s) && !freq(opposite(s))) { answer = s; break; } int i = m - 1; while (i >= 0 && s[i] == 'Y') { s[i] = 'N'; --i; } if (i < 0) break; s[i] = 'Y'; } } cout << (answer.empty() ? "-1" : answer) << '\n'; }
- 1