2022 年牛客多校第十场签到题题解
Shannon Switching Game?
https://ac.nowcoder.com/acm/contest/33195/F
F Shannon Switching Game?
题意:给定一个多重无向图 和一对点 ,起始时 处有一个令牌。先手可以选择删除图上的一条边,后手可以选择删除令牌所在点 邻接的一条边 ,然后将令牌移动到 。当令牌移动到 时后手获胜,否则先手胜。问最终结局。。
解法:若令牌所处的位置确定,则胜负已分。显然若令牌在 处为一个必胜态,若某个节点能到达两个及以上的必胜态,则该节点也为必胜态——因为先手没办法删完该点通向必胜态的边。所以倒过来从 开始 bfs 找必胜态节点即可。总时间复杂度 。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int caset, n, m, s, t;
scanf("%d", &caset);
while (caset--)
{
scanf("%d%d%d%d", &n, &m, &s, &t);
vector<vector<int>> deg(n + 1, vector<int>(n + 1, 0));
vector<vector<int>> g(n + 1);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
deg[u][v]++;
deg[v][u]++;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> vis(n + 1), in(n + 1, 0);
queue<int> q;
vis[t] = 1;
q.push(t);
while (!q.empty())
{
int tp = q.front();
q.pop();
for (auto i : g[tp])
{
if (deg[tp][i] > 1)
{
if (!vis[i] && vis[tp])
{
vis[i] = 1;
q.push(i);
}
}
else if (deg[tp][i] == 1 && vis[tp])
in[i]++;
if (in[i] >= 2 && !vis[i])
{
vis[i] = 1;
q.push(i);
}
}
}
if (vis[s])
printf("Join Player\n");
else
printf("Cut Player\n");
}
return 0;
}
H Wheel of Fortune
题意:给定 个数字 ,从中随机选择一个数字 使得 ,直到 或者 。问有多大概率 的结束游戏。
解法:显然随机选择数字只和 有关。记 ,,则只需要让 被选择 次之前 不被选择到 次即可,且最后一击必须是抽中 。答案为 。
I Yet Another FFT Problem?
题意:给定长度分别为 的序列 ,问是否存在四个下标 满足 且 。,。
解法:不妨减少限制 和 ,则可脱去绝对值有 ,即 。那么问题转化为,从 中分别选一个数使得他们碰撞。由于 ,则 ,因而用鸽巢原理可得, 序列长度不超过 就必然产生碰撞。所以仅需要保留 序列的前 项即可。总时间复杂度 ,其中 代表 的值域。
#include <bits/stdc++.h>
#define fp(i, a, b) for (int i = a, i##_ = (b) + 1; i < i##_; ++i)
#define fd(i, a, b) for (int i = a, i##_ = (b) - 1; i > i##_; --i)
using namespace std;
const int N = 2e7 + 5;
using pii = pair<int, int>;
int n, m;
pii w[N];
unordered_map<int, vector<int>> A, B;
void Solve() {
scanf("%d%d", &n, &m);
for (int x, i = 1; i <= n; ++i) scanf("%d", &x), A[x].push_back(i);
for (int x, i = 1; i <= m; ++i) scanf("%d", &x), B[x].push_back(i);
vector<pii> a, b;
pii ma, mb;
for (auto &[i, v] : A) {
a.push_back({i, v[0]});
if (v.size() > 1) ma = {v[0], v[1]};
}
for (auto &[i, v] : B) {
b.push_back({i, v[0]});
if (v.size() > 1) mb = {v[0], v[1]};
}
if (ma.first && mb.first)
return printf("%d %d %d %d\n", ma.first, ma.second, mb.first, mb.second), void();
b.resi***(b.size(), size_t(2e7 / a.size())));
for (auto &[x, i] : a)
for (auto &[y, k] : b) {
auto [j, l] = w[x + y];
if (j && i != j && k != l) {
printf("%d %d %d %d\n", i, j, k, l);
return;
} else w[x + y] = {i, k};
}
puts("-1");
}
int main() {
int t = 1;
while (t--) Solve();
return 0;
}