update
This commit is contained in:
parent
c483494ac5
commit
85df9dbbf1
44
src/7/15/U86021.cpp
Normal file
44
src/7/15/U86021.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
using ll =int64_t;
|
||||
ll n,m,a,b;
|
||||
std::vector<std::string> ans;
|
||||
std::map<std::string, ll> ansm;
|
||||
|
||||
std::variant<std::string,std::monostate> findAnsFromNum(ll n){
|
||||
for(auto &s:ansm){
|
||||
if(s.second==n){
|
||||
return s.first;
|
||||
}
|
||||
}
|
||||
return std::monostate();
|
||||
}
|
||||
|
||||
int main(){
|
||||
std::iostream::sync_with_stdio(false);
|
||||
std::cin.tie(nullptr);
|
||||
std::cout.tie(nullptr);
|
||||
|
||||
std::cin>>n>>m>>a>>b;
|
||||
ans.resize(n+1);
|
||||
for(ll i=1;i<=n;i++){
|
||||
std::string s;
|
||||
std::cin>>s;
|
||||
ansm[s]++;
|
||||
ans[i]=std::move(s);
|
||||
}
|
||||
auto findr = findAnsFromNum(a);
|
||||
if(std::string* ptr = std::get_if<std::string>(&findr)){
|
||||
std::cout<<*ptr<<'\n';//TODO 检查相反串及特殊情况
|
||||
}else{
|
||||
|
||||
}
|
||||
}
|
184
src/7/15/U86021.md
Normal file
184
src/7/15/U86021.md
Normal file
@ -0,0 +1,184 @@
|
||||
### 题目分析
|
||||
May 的班级有 $n$ 位同学,考试包含 $m$ 道判断题。每位同学的答案是一个长度为 $m$ 的字符串(仅包含 'N' 或 'Y')。老师宣布有 $a$ 位同学满分(答案完全正确),$b$ 位同学 0 分(答案完全错误),其余同学既不是满分也不是 0 分。May 知道正确答案,但需要你输出字典序最小的正确答案字符串,若无解则输出 `-1`。
|
||||
|
||||
### 解题思路
|
||||
1. **问题分析**:
|
||||
- 满分条件:答案字符串与正确答案完全相同。
|
||||
- 0 分条件:答案字符串与正确答案完全相反(即每位答案都相反)。
|
||||
- 需要找到正确答案 $s$,使得:
|
||||
- 恰好 $a$ 个同学的答案等于 $s$。
|
||||
- 恰好 $b$ 个同学的答案等于 $s$ 的相反串 $t$。
|
||||
- 其余同学的答案既不是 $s$ 也不是 $t$。
|
||||
|
||||
2. **关键观察**:
|
||||
- 如果 $a > 0$,则正确答案 $s$ 必须在输入中出现,且出现次数恰好为 $a$。
|
||||
- 如果 $b > 0$,则 $s$ 的相反串 $t$ 必须在输入中出现,且出现次数恰好为 $b$。
|
||||
- 如果 $a = 0$ 且 $b > 0$,则 $s$ 不在输入中,但 $t$ 在输入中出现次数为 $b$。
|
||||
- 如果 $a = b = 0$,则 $s$ 及其相反串 $t$ 都不在输入中,需要找到字典序最小的满足条件的 $s$。
|
||||
|
||||
3. **算法选择**:
|
||||
- **统计频率**:使用 `map` 统计每个答案字符串的出现次数。
|
||||
- **处理 $a > 0$ 或 $b > 0$ 的情况**:
|
||||
- 枚举出现次数为 $a$ 的字符串 $s$,检查其相反串 $t$ 的出现次数是否满足 $b$ 的条件。
|
||||
- 枚举出现次数为 $b$ 的字符串 $t$,生成 $s$ 为 $t$ 的相反串,并检查 $s$ 不在输入中(当 $a=0$)。
|
||||
- **处理 $a = b = 0$ 的情况**:
|
||||
- 构建禁止集合 `forbidden_set`,包含输入中所有字符串及其相反串。
|
||||
- 按字典序排序禁止集合。
|
||||
- 从全 'N' 的字符串开始,按字典序递增寻找第一个不在禁止集合中的字符串。
|
||||
|
||||
4. **复杂度分析**:
|
||||
- 统计频率:$O(n \cdot m)$。
|
||||
- 枚举候选答案:$O(k \cdot m)$,其中 $k$ 是去重后的字符串数量($k \leq n$)。
|
||||
- 处理 $a = b = 0$:排序禁止集合 $O(n \log n \cdot m)$,扫描 $O(n \cdot m)$。
|
||||
- 总体复杂度:$O(n \cdot m)$,满足数据规模要求。
|
||||
|
||||
### 代码实现
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
// 生成字符串的相反串
|
||||
string opposite(string s) {
|
||||
string res = s;
|
||||
for (char &c : res) {
|
||||
if (c == 'N')
|
||||
c = 'Y';
|
||||
else
|
||||
c = 'N';
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// 计算字典序下一个字符串
|
||||
string next_string(string s, int m) {
|
||||
string res = s;
|
||||
int i = m - 1;
|
||||
while (i >= 0 && res[i] == 'Y') {
|
||||
res[i] = 'N';
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
res[i] = 'Y';
|
||||
return res;
|
||||
} else {
|
||||
return ""; // 溢出,无下一个字符串
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n, m, a, b;
|
||||
cin >> n >> m >> a >> b;
|
||||
vector<string> inputs(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> inputs[i];
|
||||
}
|
||||
|
||||
// 统计每个答案字符串的出现频率
|
||||
map<string, int> freq;
|
||||
for (string s : inputs) {
|
||||
freq[s]++;
|
||||
}
|
||||
|
||||
if (a > 0 || b > 0) {
|
||||
set<string> candidates;
|
||||
|
||||
// 处理 a > 0 的情况
|
||||
if (a > 0) {
|
||||
for (auto &p : freq) {
|
||||
string s = p.first;
|
||||
int cnt = p.second;
|
||||
if (cnt == a) {
|
||||
string opp = opposite(s);
|
||||
if (b > 0) {
|
||||
// 检查相反串出现次数是否为 b
|
||||
if (freq.count(opp) && freq[opp] == b) {
|
||||
candidates.insert(s);
|
||||
}
|
||||
} else {
|
||||
// 检查相反串不在输入中
|
||||
if (!freq.count(opp)) {
|
||||
candidates.insert(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理 b > 0 且 a = 0 的情况
|
||||
if (b > 0 && a == 0) {
|
||||
for (auto &p : freq) {
|
||||
string t = p.first;
|
||||
int cnt = p.second;
|
||||
if (cnt == b) {
|
||||
string s_candidate = opposite(t);
|
||||
// 检查 s_candidate 不在输入中
|
||||
if (!freq.count(s_candidate)) {
|
||||
candidates.insert(s_candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 输出字典序最小的候选答案
|
||||
if (candidates.empty()) {
|
||||
cout << "-1" << endl;
|
||||
} else {
|
||||
cout << *candidates.begin() << endl;
|
||||
}
|
||||
} else {
|
||||
// 处理 a = 0 且 b = 0 的情况
|
||||
set<string> forbidden_set;
|
||||
for (auto &p : freq) {
|
||||
string s = p.first;
|
||||
forbidden_set.insert(s);
|
||||
string opp = opposite(s);
|
||||
forbidden_set.insert(opp);
|
||||
}
|
||||
|
||||
// 将禁止集合排序
|
||||
vector<string> forbidden_vec(forbidden_set.begin(), forbidden_set.end());
|
||||
sort(forbidden_vec.begin(), forbidden_vec.end());
|
||||
|
||||
string candidate = string(m, 'N'); // 从全 'N' 开始
|
||||
bool valid = true;
|
||||
int i = 0;
|
||||
while (i < forbidden_vec.size()) {
|
||||
if (candidate < forbidden_vec[i]) {
|
||||
break; // 找到不在禁止集合中的字符串
|
||||
} else if (candidate > forbidden_vec[i]) {
|
||||
i++; // 跳过较小的禁止字符串
|
||||
} else {
|
||||
candidate = next_string(candidate, m); // 生成下一个字符串
|
||||
if (candidate == "") {
|
||||
valid = false; // 无有效下一个字符串
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
cout << "-1" << endl;
|
||||
} else {
|
||||
cout << candidate << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 代码解释
|
||||
1. **输入处理**:读取同学数量 $n$、题目数量 $m$、满分人数 $a$、0 分人数 $b$ 以及所有同学的答案字符串。
|
||||
2. **频率统计**:使用 `map` 统计每个答案字符串的出现次数。
|
||||
3. **候选答案生成**:
|
||||
- 当 $a > 0$ 或 $b > 0$ 时,枚举满足条件的字符串(出现次数为 $a$ 或 $b$),并检查其相反串的条件。
|
||||
- 当 $a = b = 0$ 时,构建禁止集合并按字典序排序,从全 'N' 的字符串开始,按字典序递增寻找第一个不在禁止集合中的字符串。
|
||||
4. **输出结果**:若有候选答案,输出字典序最小的;若无解,输出 `-1`。
|
||||
|
||||
此解法高效处理了各种情况,特别是利用字典序递增生成字符串的方法,确保在 $a = b = 0$ 时也能快速找到最小字典序答案。
|
140
src/7/15/U86021ds.cpp
Normal file
140
src/7/15/U86021ds.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
|
||||
string oppo(string s) {
|
||||
string res = s;
|
||||
for (char &c : res) {
|
||||
if (c == 'N')
|
||||
c = 'Y';
|
||||
else
|
||||
c = 'N';
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
string next_string(string s, int m) {
|
||||
string res = s;
|
||||
int i = m - 1;
|
||||
while (i >= 0 && res[i] == 'Y') {
|
||||
res[i] = 'N';
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
res[i] = 'Y';
|
||||
return res;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::iostream::sync_with_stdio(false);
|
||||
std::cin.tie(nullptr);
|
||||
std::cout.tie(nullptr);
|
||||
int n, m, a, b;
|
||||
cin >> n >> m >> a >> b;
|
||||
vector<string> inputs(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
cin >> inputs[i];
|
||||
}
|
||||
|
||||
|
||||
map<string, int> freq;
|
||||
for (string s : inputs) {
|
||||
freq[s]++;
|
||||
}
|
||||
|
||||
if (a > 0 || b > 0) {
|
||||
set<string> candidates;
|
||||
|
||||
|
||||
if (a > 0) {
|
||||
for (auto &p : freq) {
|
||||
string s = p.first;
|
||||
int cnt = p.second;
|
||||
if (cnt == a) {
|
||||
string opp = oppo(s);
|
||||
if (b > 0) {
|
||||
|
||||
if (freq.count(opp) && freq[opp] == b) {
|
||||
candidates.insert(s);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!freq.count(opp)) {
|
||||
candidates.insert(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (b > 0 && a == 0) {
|
||||
for (auto &p : freq) {
|
||||
string t = p.first;
|
||||
int cnt = p.second;
|
||||
if (cnt == b) {
|
||||
string s_candidate = oppo(t);
|
||||
|
||||
if (!freq.count(s_candidate)) {
|
||||
candidates.insert(s_candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (candidates.empty()) {
|
||||
cout << "-1" << endl;
|
||||
} else {
|
||||
cout << *candidates.begin() << endl;
|
||||
}
|
||||
} else {
|
||||
|
||||
set<string> forbidden_set;
|
||||
for (auto &p : freq) {
|
||||
string s = p.first;
|
||||
forbidden_set.insert(s);
|
||||
string opp = oppo(s);
|
||||
forbidden_set.insert(opp);
|
||||
}
|
||||
|
||||
|
||||
vector<string> forbidden_vec(forbidden_set.begin(), forbidden_set.end());
|
||||
sort(forbidden_vec.begin(), forbidden_vec.end());
|
||||
|
||||
string candidate = string(m, 'N');
|
||||
bool valid = true;
|
||||
int i = 0;
|
||||
while (i < forbidden_vec.size()) {
|
||||
if (candidate < forbidden_vec[i]) {
|
||||
break;
|
||||
} else if (candidate > forbidden_vec[i]) {
|
||||
i++;
|
||||
} else {
|
||||
candidate = next_string(candidate, m);
|
||||
if (candidate == "") {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
cout << "-1" << endl;
|
||||
} else {
|
||||
cout << candidate << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user