题解:P11601 『Fwb』狼人の杀戮
upd on 2025/1/22:增加猎人多次开枪情况。
根据题意模拟即可,这里直接总结。
输入会有错误的点
- 发动技能的人与职业不对应。
- 一个人发动多次技能。
- 猎人死了没开枪。
- 有人杀死了已经死了的人或自杀。
- 女巫救了活着的人。
- 女巫没药还发动技能。
- 女巫不能救非今夜死亡的人。
- 编号有误。
注意
- 本题可能有很多个女巫和很多个猎人。
- 女巫可以自救。
- 猎人开枪时必须自己处于死亡状态,无论是否后续有女巫救。
- 民其实没必要单独拿出来判。
- 猎人可以多次开枪,为了便于实现,女巫救猎人时认为被救的猎人没开过枪,即将
vis 数组置为0 。
为了简化输入有错后的「撤销」操作考虑新开一个东西存然后 memcpy。
code 非常简单,个人认为和 CSP 那道差不多。
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
#define rep(i, j, k) for(int i = j; i <= k; ++i)
#define pre(i, j, k) for(int i = j; i >= k; --i)
#define pb push_back
using namespace std;
const int N = 66;
int n, m, q, cnt, flg, a[N], b[N], B[N], vis[N];
int tag[N][4], ID;
//1狼 2民 3枪 4女
bool check(int op, int x, int y) {
if(!(1 <= x && x <= n) || !(1 <= y && y <= n)) return false;
//assert(!(x == y && a[x]==4));
if(a[x] == 4 && x == y && !vis[x] && B[x] && tag[x][3]) return B[x] = 0, vis[x] = 1, tag[x][3] = 0, true;//女巫自救
else if(a[x] == 4 && x == y) return false;
if(B[x] && a[x] != 3 || a[x] == 2 || vis[x]) return false;
if(op == 0) {//狼刀
if(a[x] != 1 || x == y || B[y]) return false;
B[y] = vis[x] = 1;
}
if(op == 1) {//女毒
if(a[x] != 4 || x == y || B[y] || !tag[x][2]) return false;
B[y] = 1;
tag[x][2] = 0;
vis[x] = 1;
}
if(op == 2) {//女救
if(a[x] != 4 || b[y] || !B[y] || !tag[x][3]) return false;
B[y] = 0;
tag[x][3] = 0;
vis[x] = 1;
if(a[y] == 3) vis[y] = 0;//女巫救活猎人
}
if(op == 3) {//开枪
if(a[x] != 3 || !B[x] || B[y] || x == y) return false;
B[y] = 1;
vis[x] = 1;
}
return true;
}
signed main() {
FASTIO
cin >> q >> n;
rep(i, 1, n) cin >> a[i], tag[i][0] = tag[i][1] = 1;
while(q--) {
++ID;
memset(vis, 0, sizeof vis);
memcpy(B, b, sizeof b);
cnt = flg = 0;
rep(i, 1, n) tag[i][2] = tag[i][0], tag[i][3] = tag[i][1];
cin >> m;
while(m--) {
int op, x, y;
cin >> op >> x >> y;
if(!check(op, x, y)) {
// cout << '!' << op << ' ' << x << ' ' << y << '\n';
flg = 1;
continue;
}
// rep(i, 1, n) cout << B[i] << ' ';
// cout << '\n';
}
rep(i, 1, n) if(b[i] == 0 && B[i] == 1 && a[i] == 3 && !vis[i]) flg = 1;//判断是否有死了的猎人没开枪
if(flg) cout << "Wrong\n";
else {
vector<int> p;
rep(i, 1, n) if(b[i] == 0 && B[i] == 1) p.pb(i);
cnt = p.size();
if(!cnt) cout << "Safe\n";
else {
cout << cnt << ' ';
for(auto x : p) cout << x << ' ';
cout << '\n';
}
memcpy(b, B, sizeof b);
rep(i, 1, n) tag[i][0] = tag[i][2], tag[i][1] = tag[i][3];
}
}
}