长春集训 Day 2 - 数学专题 2
长春集训 Day 2 - 数学专题 2
A - Long Shuffle
Description
给定长度为 \(n\) 的序列 \(a\),满足 \(\forall i \in [1, n]\),\(a_i = i\)。
定义一次操作 \(f(l,r)\) 满足:
- 若 \(r - l = 1\),则 \(\mathrm{swap}(a_l, a_r)\)。
- 否则,先 \(f(l,r-1)\),再 \(f(l + 1,r)\)。
现执行 \(f(1,n)\),给定 \(k\),求出操作后 \(a_k\) 的值。
多测,\(1 \le T \le 1000\),\(2 \le n \le 10^{18}\)。
Solution
数学归纳法
数学归纳法是一种优秀的证明手段,常用于证明某命题对所有自然数成立的情况。
其主旨为边界 + 递推。
步骤:对于命题 \(P(n)\),
- 证明命题 \(P(n_0)\) 成立。
- 假设命题 \(P(k-1)\) 成立,证明命题 \(P(k)\) 成立。
- 可以推出 \(\forall n \ge n_0\),\(P(n)\) 都成立。
我们现在使用数学归纳法证明本题的一些引理。
关键观察
当 \(n\) 为偶数时,只会交换相邻两个位置的数字。
可以打表观察出来。
先证明 \(n\) 为偶数时操作 \(f(l,r)\) 自反,即经两次相同操作后序列不变。
显然 \(n=2\) 时操作自反。
假设 \(n = k-2\) 时操作自反,则 \(f(l,r)\) 可拆为 \(f(l,r-1)\) 和 \(f(l + 1,r)\),进而拆为 \(f(l,r-2),f(l+1,r-1),f(l+1,r-1),f(l+2,r)\)。
对于上面的四个操作,由假设知它们自反,即 \(n=k\) 时操作自反。于是得证。
再证明邻项交换的性质。
显然 \(n=2\) 时成立。
假设 \(n=n-2\) 时结论成立,则 \(f(1,n)\) 可拆为 \(f(1,n-2),f(2,n-1),f(2,n-1),f(3,n)\)。
根据自反性,中间两项可以消去;根据假设,\([1,n-2]\) 与 \([3,n]\) 均被邻项交换。中间重叠的部分经由两次邻项交换,仍然发生了邻项交换。因此结论在 \(n=n\) 时成立。证毕。
递推
设 \(dp_{i,j}\) 表示序列 \([1,2n]\) 经由 \(f\) 操作后,位置 \(2j-1\) 与 \(2j\) 是否发生交换。
显然 \([1,2n] \to [1,2n-1],[2,2n]\)。
对于拆后的两个区间,变量 \(j\) 在其中的相对位置分别为 \(j\) 和 \(j-1\),因此有
即
显然,边界为
我们熟知
若令
则
与 \(dp\) 的递推式构型相同。检查边界:
- \(i = j\) 时,\(dp_{i,i} = g_{i,i} = \dbinom{i-1}{i-1}=1\),一致。
- \(j = 1\) 时,\(dp_{i,1} = g_{i,1} = \dbinom{i-1}{0} = 1\),一致。
综上,函数 \(g\) 与 \(dp\) 具有相同递推关系,即
值得注意的是,这里定义 \(g_{i,j} = \dbinom{i-1}{j-1}\) 而非 \(\dbinom{i}{j}\) 的原因是,计算 \(\dbinom{i}{1}\) 时,第二条边界并不相符。需要构造出一个与其相符的组合递推式,于是选用 \(\dbinom{i-1}{j-1}\)。
奇偶性判断
现在要计算 \(dp_{i,j}\) 的值,就要计算 \(\dbinom{i-1}{j-1}\) 的奇偶性。
引理 2 \(\dbinom ij \equiv 1 \pmod 2 \iff i \& j = j\),其中 \(\&\) 表示按位与。
记 \(i_p\) 表示 \(i\) 在二进制下的第 \(p\) 位。根据 Lucas 定理,有
即
又因为 \(i_p,j_p \in \{0,1\}\),而当且仅当 \(i_p=0, j_p=1\) 时才有 \(\dbinom 01 \equiv 0 \pmod 2\),因此可知当 \(i\&j=j\) 时,一定有 \(\dbinom ij \equiv 1 \pmod 2\)。
答案计算
当 \(n\) 为偶数时,计算 \(dp_{n/2,\lceil k/2 \rceil}\) 即可。
当 \(n\) 为奇数时,拆为两个偶数的子问题即可。
Code
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define int long long
#define inf 1e18
#define debug cout << '!';
#define filein(x) freopen(#x".in", "r", stdin);
#define fileout(x) freopen(#x".out", "w", stdout);
#define file(x) filein(x) fileout(x)
using namespace std;
int T, n, k;
int solve(int l, int r, int v) {
r -= l - 1, v -= l - 1;
if (((r / 2 - 1) & ((v + 1) / 2 - 1)) != ((v + 1) / 2) - 1) return v + l - 1;
if (v & 1) v++; else v--; return v + l - 1;
}
signed main() {
cin.tie(0) -> sync_with_stdio(0);
cin >> T;
while (T--) {
cin >> n >> k;
if (n & 1) cout << solve(1, n - 1, solve(2, n, k)) << '\n';
else cout << solve(1, n, k) << '\n';
}
return 0;
}
B - mod M Game
Description
给定长度为 \(2n\) 的数组 \(a\),并给定整数 \(m(m \ge 2)\)。
Alice 和 Bob 轮流游戏,Alice 先手。每次操作需选择数组中的一个数,并将其消去。
记 Alice 消去的数之和为 \(x\),Bob 消去的数之和为 \(y\),当游戏结束后,若 \(x \equiv y \pmod m\),则 Bob 获胜,否则 Alice 获胜。
若双方都采取最优策略,则谁会获胜。
Solution
直接转化很难,考虑缩小局面,将其定格在最后一局。
考虑待定两人在倒数第二轮以及之前消去的数之和分别为 \(x\) 和 \(y\),剩下的两个数分别为 \(a\) 和 \(b\)。
此时必定 Alice 执子。当且仅当同时满足 \(\begin{cases} x+a \equiv y+b \pmod m \\ y+a \equiv x+b \pmod m \end{cases}\) 时 Bob 必胜。
将上两式相加,得 \(2a \equiv 2b \pmod m \land x - y \equiv a - b \pmod m\)。
暂先不考虑第二个条件,只考虑 \(2a \equiv 2b \pmod m\)。钦定 \(a<b\),由此推出上式等价于
这即是说,当 Alice 选择一个数时,当且仅当 Bob 能根据上式找到于之匹配的所有数时,他必胜。
对于条件 \(a=b\),可以直接从原数组中消去。对于剩余的数:
- 如果不存在剩余的数,Alice 没招了,则 Bob 必胜;
- 如果 \(m\) 为奇数,显然不满足第二个条件,则 Alice 必胜。
- 如果存在 \(a\) 但不存在 \(b\) 使得 \(b = (a + \dfrac m2) \bmod m\),则也不满足第二条件,则 Alice 必胜。
这仍然不是充要的,原因在于没考虑条件 \(x \equiv y \pmod m\)。每当选择数对 \((a, b)\) 使得 \(b = (a + \dfrac m2) \bmod m\) 时,\(x-y\) 都会增加 \(\dfrac m2\)。进而,当且仅当选择这种数对的个数为偶数时,才能使得第二个条件成立,此时 Bob 必胜,否则 Alice 必胜。
Code
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define int long long
#define inf 1e18
#define debug cout << '!';
#define filein(x) freopen(#x".in", "r", stdin);
#define fileout(x) freopen(#x".out", "w", stdout);
#define file(x) filein(x) fileout(x)
using namespace std;
int n, m;
set<int> s;
signed main() {
cin.tie(0) -> sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= 2 * n; i++) {
int x; cin >> x;
if (not s.count(x)) s.insert(x);
else s.erase(x);
}
int cnt = 0;
for (int x : s) {
if (m & 1) {
cout << "Alice\n";
return 0;
}
if (not s.count((x + m / 2) % m)) {
cout << "Alice\n";
return 0;
}
cnt++;
}
cnt /= 2;
if (cnt & 1) cout << "Alice\n";
else cout << "Bob\n";
return 0;
}
E - Not Equal Rectangle
Description
有一个 \(n \times m\) 的表格 \(a\),需要在每个格子中写入一个 \(1 \sim 25\) 的整数,保证满足 \(\forall 1 \le x_1 \lt x_2 \le n, 1 \le y_1 \lt y_2 \le m, a_{x_1,y_1},a_{x_1,y_2},a_{x_2,y_1},a_{x_2,y_2}\) 不全相同。给出一种构造方案。
\(2 \le n,m \le 500\)。
Solution
给定质数 \(p\),使原网格划分为 \(p^2\) 个大小为 \(p \times p\) 的宫。对于每个宫 \(M\),若其满足 \(M_{i,j} = (i + j + k) \bmod p\),则称之为 \(k\) 类宫。这类宫满足在宫内选取任意一个长方形,总有该长方形的四角不全相同。
对于所求矩阵 \((i,j)\) 处的宫,令其为 \(ij \bmod p\) 类宫即可。
这样构造矩阵可以满足题意。
证明采用反证法:若存在四角完全相同的矩阵,那么记左上、右上、左下、右下的宫分别是 \(a,b,c,d\) 类宫,则根据宫的定义必有 \(a-b \equiv c-d \pmod p\),但不可能发生。于是得证。
现在不太清楚这种构造方案是怎么想出来的,需要再顺序地仔细思考一下。
Code
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
#define int long long
#define inf 1e18
#define debug cout << '!';
#define filein(x) freopen(#x".in", "r", stdin);
#define fileout(x) freopen(#x".out", "w", stdout);
#define file(x) filein(x) fileout(x)
using namespace std;
const int B = 23;
int n, m;
signed main() {
cin.tie(0) -> sync_with_stdio(0);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << ((i / B) * (j / B) + i + j) % B + 1 << ' ';
}
cout << '\n';
}
return 0;
}

浙公网安备 33010602011771号