题解 P11234【[CSP-S 2024] 擂台游戏】
这道题的整个题面都要读,根本简化不了。
题目描述
小 S 想要举办一场擂台游戏,如果共有
- 第一轮编号为
的选手进行一次对局,编号为 的选手进行一次对局,以此类推,编号为 的选手进行一次对局。 - 第二轮在只保留第一轮的胜者的前提下,相邻的两位依次进行一场对局。
- 以此类推,第
轮在只保留第 轮的 位胜者的前提下,前两位、后两位分别进行对局,也就是所谓的半决赛。 - 第
轮即为半决赛两位胜者的决赛。
确定了游戏晋级的规则后,小 S 将比赛的规则设置为了擂台赛。具体而言,每位选手都有一个能力值
现在,小 S 先后陆续收到了
形式化地,设
当然小 S 觉得这个问题还是太简单了,所以他给了你
输入格式
本题的测试点包含有多组测试数据。 但不同测试数据只是通过修改
输入的第一行包含两个正整数
输入的第二行包含
输入的第三行包含
设
注意,由于询问只是将人数凑齐到
接下来一行包含一个正整数
接下来共
输出格式
共输出
样例 #1
样例输入 #1
5 5
0 0 0 0 0
5 4 1 2 3
1001
10
1
4
2 1 0 0
1 2 1 0
0 2 3 1
2 2 0 1
样例输出 #1
5
19
7
1
提示
【样例 1 解释】
共有
- 对于长度为
的前缀,由于只有 号一个人,因此答案为 。 - 对于长度为
的前缀,由于 个人已经是 的幂次,因此不需要进行扩充。根据抽签 可知 号为擂主,由于 ,因此 号获胜,答案为 。 - 对于长度为
的前缀,首先 号、 号比赛是 号获胜(因为 ,故 号为擂主, ),然后虽然 号能力值还不知道,但 号、 号比赛一定是 号获胜(因为 ,故 号为擂主, ),而决赛 号、 号谁获胜都有可能(因为 ,故 号为擂主,如果 则 号获胜, 则 号获胜)。综上所述,答案为 。 - 对于长度为
的前缀,我们根据上一条的分析得知,由于 ,所以决赛获胜的是 号。 - 对于长度为
的前缀,可以证明,可能获胜的选手包括 号、 号、 号,答案为 。
因此,该组测试数据的答案为
【样例 2】
见选手目录下的 arena/arena2.in 与 arena/arena2.ans。
这组样例满足特殊性质 A。
【样例 3】
见选手目录下的 arena/arena3.in 与 arena/arena3.ans。
这组样例满足特殊性质 B。
【样例 4】
见选手目录下的 arena/arena4.in 与 arena/arena4.ans。
【样例 5】
见选手目录下的 arena/arena5.in 与 arena/arena5.ans。
【数据范围】
对于所有测试数据,保证:
测试点 | 特殊性质 A | 特殊性质 B | ||
---|---|---|---|---|
否 | 否 | |||
是 | 否 | |||
否 | 是 | |||
否 | 否 | |||
是 | 否 | |||
否 | 是 | |||
否 | 否 | |||
否 | 否 | |||
否 | 否 | |||
否 | 否 | |||
否 | 否 |
特殊性质 A:保证询问的
特殊性质 B:保证所有的
solution 84
枚举最后补全到
这个游戏就是一个二叉树结构,直接建类似 zkw 线段树的结构方便考虑。考虑第
表示擂主方赢的部分。如果 那么擂主可以输掉, 额外 上 。 表示赢的擂主的编号和(可能输的擂主已经枪毙)。如果 那么擂主可以输掉, 额外 上 。
维护之,复杂度
solution 100
为了优化,提出重要性质:
归纳证明:归纳基石显然。
- 擂主是伪人,则结果还是伪人,但其实擂主的
存在 部分,但不影响结果是伪的。 - 擂主是真人,若真人的能力值
则结果是他,否则结果要么是另一个真人要么是伪人,伪人上来之后伪人性质继续保持。
“在同一个
可以对每个结点处理出
计算了
ref:https://www.luogu.com.cn/article/mmehkagt
code
84
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#define endl "\n"
#endif
using LL = long long;
int n, m, a0[200010], cq[200010], up[400010], K;
bool rev[400010];
LL ans[200010], sum[400010];
void maintain(int p) {
int lc = p << 1, rc = p << 1 | 1, R = K - __lg(p);
if (rev[p]) swap(lc, rc);
int lo = up[lc] & ((1 << R) - 1);
up[p] = up[lc] - lo;
sum[p] = sum[lc];
if (lo) up[p] |= up[rc];
if (lo) sum[p] += sum[rc];
}
int mian() {
int X[4];
for (int i = 0; i < 4; i++) cin >> X[i];
for (int i = 1; i < 1 << (K + 1); i++) up[i] = (1 << 18) - 1;
for (int i = 0; i < 1 << K; i++) sum[(1 << K) + i] = i + 1;
for (int i = (1 << K) - 1; i >= 1; i--) sum[i] = sum[i << 1] + sum[i << 1 | 1];
int ansp = (1 << K);
for (int i = 0; i < n; i++) {
int p = (1 << K) + i, v = a0[i] ^ X[(i + 1) % 4];
up[p] = 1 << min(v, 17);
for (int q = p; q > ansp && sum[p] && v < 17; q >>= 1) if ((q & 1) == rev[q >> 1] && v < K - __lg(q >> 1)) sum[p] = 0;
while ((p >>= 1) >= ansp) maintain(p);
ans[i + 1] = sum[ansp];
#ifdef LOCAL
if ((i & (i + 1)) == 0) debug("ans[%d] = %d\n", i + 1, ans[i + 1]);
// for (int i = 1; i < 1 << (K + 1); i++) debug("up[%d] = %s\n", i, bitset<18>(up[i]).to_string().c_str());
// for (int i = 1; i < 1 << (K + 1); i++) debug("sum[%d] = %lld\n", i, sum[i]);
#endif
if ((i & (i + 1)) == 0) {
ansp >>= 1;
if (!rev[ansp]) {
int R = K - __lg(ansp);
debug("R = %d\n", R);
for (int j = 0; j <= i; j++) {
int v = a0[j] ^ X[(j + 1) % 4];
if (v < R) sum[(1 << K) + j] = 0;
}
for (int j = R - 1; j >= 0; j--) for (int i = ansp << j; i < ((ansp + 1) << j) - (j ? 1 << (j - 1): 0); i++) maintain(i);
}
}
}
LL fans = 0;
for (int i = 1; i <= m; i++) fans ^= 1ll * i * ans[cq[i]];
cout << fans << endl;
return 0;
}
int main() {
#ifndef LOCAL
#ifdef NF
freopen("arena.in", "r", stdin);
freopen("arena.out", "w", stdout);
#endif
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n >> m;
while (1 << K < n) ++K;
for (int i = 0; i < n; i++) cin >> a0[i];
for (int i = 1; i <= m; i++) cin >> cq[i];
for (int k = 1; k <= K; k++) {
static char buf[200010];
cin >> buf;
int st = 1 << (K - k);
for (int i = 0; i < st; i++) rev[st + i] = buf[i] == '1';
}
int t;
cin >> t;
while (t--) mian();
return 0;
}
100
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
#define lg __lg
using LL = long long;
int n, m, cq[100010], K, a0[200010], tim[400010], a[400010], atm[400010], pos[200010][18];
bool rev[400010];
LL ans[400010];
int mian() {
int X[4];
for (int &x : X) cin >> x;
for (int i = 0; i < n; i++) a[1 << K | i] = a0[i] ^ X[(i + 1) & 3], tim[1 << K | i] = i, ans[i] = 0;
for (int i = n; i < 1 << K; i++) tim[1 << K | i] = i;
ans[0] = 1, ans[1] = -1;
for (int k = 1; k <= K; k++) {
debug("k = %d\n", k);
for (int i = 1; i <= k; i++) {
for (int j = 0; j < 1 << (k - i); j++) {
int p = (1 << (K - i)) + j;
int lc = p << 1 | rev[p], rc = p << 1 | !rev[p], R = K - lg(p);
debug("p = %d, R = %d\n", p, R);
if (a[lc] >= R) tim[p] = tim[lc], a[p] = a[lc], debug("?");
else tim[p] = max(tim[lc], tim[rc]), a[p] = a[rc], debug("!");
debug("rev[%d] = %d, a[%d] = %d, tim[%d] = %d\n", p, rev[p], p, a[p], p, tim[p]);
}
}
atm[1 << (K - k)] = min(n, 1 << k);
for (int i = k; i >= 1; i--) {
for (int j = 0; j < 1 << (k - i); j++) {
int p = (1 << (K - i)) + j;
debug("p = %d\n", p);
debug("atm[%d] = %d\n", p, atm[p]);
int lc = p << 1 | rev[p], rc = p << 1 | !rev[p], R = K - lg(p);
atm[lc] = atm[p];
if (a[lc] >= R) atm[rc] = min(atm[p], tim[p]);
else atm[rc] = atm[p];
}
}
int st = 1 << (k - 1);
debug("st = %d\n", st);
for (int i = 0; i < 1 << k; i++) {
ans[st] += i + 1;
int ed = max(st, atm[1 << K | i]);
if (a[1 << K | i] < pos[i][k]) debug("!!"), ed = max(st, min(ed, i));
debug("a[%d] = %d, atm[%d] = %d, pos[%d][%d] = %d\n", i, a[1 << K | i], i, atm[1 << K | i], i, k, pos[i][k]);
if (st < ed) debug("%d -> ans[%d, %d)\n", i, st, ed);
ans[ed] -= i + 1;
}
}
for (int i = 1; i < n; i++) ans[i] += ans[i - 1];
LL fans = 0;
for (int i = 1; i <= m; i++) debug("ans[%d] = %lld\n", cq[i], ans[cq[i] - 1]), fans ^= i * ans[cq[i] - 1];
cout << fans << endl;
return 0;
}
int main() {
#ifndef LOCAL
cin.tie(nullptr)->sync_with_stdio(false);
#endif
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> a0[i];
for (int i = 1; i <= m; i++) cin >> cq[i];
while (1 << K < n) ++K;
for (int i = K - 1; i >= 0; i--) {
static char buf[200010];
cin >> buf;
for (int j = 0; j < 1 << i; j++) rev[1 << i | j] = buf[j] == '1';
}
for (int i = 0; i < n; i++) {
int p = 1 << K | i;
int lst = 0;
for (int k = 1; k <= K; k++) {
if (rev[p >> 1] == (p & 1)) lst = k;
p >>= 1;
pos[i][k] = lst;
}
}
int t;
cin >> t;
memset(a, 0, sizeof a);
while (t--) mian();
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18511197/solution-P11234
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现