2024/09/23 模拟赛总结
rk3,\(0+100+30+5=135\)
唐氏分类讨论,赛时写了个记搜爆0了
因为 \(0\) 不会改变取得数的和,所以 \(a\) 可以改为 \(a \bmod 2\)
接下来分类讨论
-
假设先手取 \(1\),那么后手取 \(2\) 直接输,则一定先取 \(1\),接下来先手取 \(1\) 又输,只能取 \(2\),然后就会循环后手 \(1\),先手 \(2\),后手 \(1\),先手 \(2\dots\)
-
假设先手取 \(2\),同理接下来会循环后手 \(2\),先手 \(1\),后手 \(2\),先手 \(1\dots\)
\(0\) 可以交换先后手,再进行一次分讨即可
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int t;
LL a, b, c;
void pr(bool pr) {
cout << (pr ? "Second" : "First") << '\n';
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
freopen("yiyi.in", "r", stdin);
freopen("yiyi.out", "w", stdout);
for (cin >> t; t; t--) {
cin >> a >> b >> c;
(a & 1) ? (pr(b ? (b - 1 <= c && c <= b + 1) : (c == 0 || c == 1))) : (pr(b == 1 ? 0 : (b ? c == 0 : c != 1)));
}
return 0;
}
赛时用了 1h 把式子推出来了,跑了 \(10^4\) 组拍子,没挂分
考虑打表找规律,令 \(v_i\) 为 \(val(p)=i\) 的方案数,显然不论如何放 \(val\) 一定不等于 \(1\),表格中不存在即没有限制。
当 \(i=2\) 时:
\(p_2\) |
---|
\(1\) |
答案为 \((n-1)!\)
当 \(i=3\) 时:
\(p_2\) 方案数 | \(p_3\) |
---|---|
\(n-1\)(除去\(1\)) | \(1\) |
\(n-2\)(除去\(1,p_3\)) | \(2\) |
答案为 \([(n-1) + (n-2)](n-2)!\)
当 \(i=4\) 时:
\(p_2\) 方案数 | \(p_3\) 方案数 | \(p_4\) |
---|---|---|
\(n-2\)(除去\(1,p_3\)) | \(n-2\)(除去\(1,2\)) | \(1\) |
\(n-3\)(除去\(1,p_3,p_4\)) | \(n-2\)(除去\(1,2\)) | \(2\) |
\(n-3\)(除去\(1,p_3,p_4\)) | \(n-3\)(除去\(1,2,p_4\)) | \(3\) |
答案为 \([(n-2)^2+(n-2)(n-3)+(n-3)^2](n-3)!\)
当 \(i=5\) 时:
\(p_2\) 方案数 | \(p_3\) 方案数 | \(p_4\) 方案数 | \(p_5\) |
---|---|---|---|
\(n-3\)(除去\(1,p_3,p_4\)) | \(n-3\)(除去\(1,2,p_4\)) | \(n-3\)(除去\(1,2,3\)) | \(1\) |
\(n-4\)(除去\(1,p_3,p_4,p_5\)) | \(n-3\)(除去\(1,2,p_4\)) | \(n-3\)(除去\(1,2,3\)) | \(2\) |
\(n-4\)(除去\(1,p_3,p_4,p_5\)) | \(n-4\)(除去\(1,2,p_4,p_5\)) | \(n-3\)(除去\(1,2,3\)) | \(3\) |
\(n-4\)(除去\(1,p_3,p_4,p_5\)) | \(n-4\)(除去\(1,2,p_4,p_5\)) | \(n-4\)(除去\(1,2,3,p_5\)) | \(4\) |
答案为 \([(n-3)^3+(n-3)^2(n-4)+(n-3)(n-4)^2+(n-4)^3](n-4)!\)
到这里已经大概看出规律了,\(n-i+2,n-i+1\) 形成了一个阶梯。
这样就可以列出式子:\(v_i=\displaystyle\sum_{j=0}^{i-2}(n-i+1)^j(n-i+2)^{i-j-2}\)。
但是这样还是 \(O(n^2)\) 的做法,考虑 \((n-i+1)+1=n-i+2\),令 \(a=n-i+1\)。
证明 \(\displaystyle\sum_{i=0}^{k}a^i(a+1)^{k-i}=(a+1)^{k+1}-a^{k+1}\)
这是一个不严谨的证明,因为我们再次使用了找规律
考虑当 \(k=5\) 时,我们展开和式:
\(\,\,\,\,\,a^5+5a^4+10a^3+10a^2+5a+1\)
\(+a^5+4a^4+6a^3\,\,\,+4a^2\,\,\,+a\)
\(+a^5+3a^4+3a^3\,\,\,+1a^2\,\,\,\)
\(+a^5+2a^4+a^3\,\,\,\)
\(+a^5+a^4\)
\(+a^5\)
按列相加得到 \(6a^5+15a^4+20a^3+15a^2+6a+1\),通过补项得到:\(a^6+6a^5+15a^4+20a^3+15a^2+6a+1-a^6=(a+1)^6-a^6\)\[\texttt{Q.E.D.} \]
直接按式子模拟即可,注意 \(k=i-2\),由于是期望,最后要除掉 \(\frac{i}{n!}\)。
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const LL kP = 998244353;
const int kMaxN = 1e6 + 5;
LL n, f[kMaxN], ans, cnt;
LL P(LL x, LL y, LL ret = 1) {
for (; y; (y & 1) && ((ret *= x) %= kP), (x *= x) %= kP, y >>= 1) {
}
return ret;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0), f[0] = 1;
freopen("wuyi.in", "r", stdin);
freopen("wuyi.out", "w", stdout);
for (int i = 1; i < kMaxN; i++) {
f[i] = f[i - 1] * i % kP;
}
cin >> n;
for (LL i = 2, tmp = 0; i <= n + 1; i++, tmp = 0) {
cnt = f[n - i + 1] * i % kP;
LL l = n - i + 1;
tmp = (P(l + 1, i - 1) - P(l, i - 1)) % kP, (tmp += kP) %= kP;
(cnt *= tmp) %= kP;
(ans += (cnt * P(f[n], kP - 2) % kP)) %= kP;
}
cout << ans << '\n';
return 0;
}
考虑前缀和,则 \(\texttt{ans}=S_r \bigoplus S_{l-1}\)
可以使用递归求解,令 \(k\) 为最大的 \(k\) 满足 \(fib_k \le n\),\(S_n=S_{fib_k-1}\bigoplus S_{n-fib_k} \bigoplus ([(n-fib_k) \bmod 2=0] \times fib_k)\)
还可以顺便记忆化一下,降低复杂度
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 1e7 + 5;
int t;
LL l, r, f[kMaxN];
unordered_map<LL, LL> mp;
LL S(LL x, LL ret = 0) {
if (x <= 0) {
return 0;
}
if (mp.count(x)) {
return mp[x];
}
for (int i = 88; i; i--) {
if (x >= f[i]) {
if (x - f[i] % 2 == 0) {
ret ^= f[i];
}
return mp[x] = ret ^ S(x - f[i]) ^ S(f[i] - 1);
}
}
return 0;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0), f[1] = 1, f[2] = 2;
freopen("yijiu.in", "r", stdin);
freopen("yijiu.out", "w", stdout);
for (int i = 3; i <= 88; i++) {
f[i] = f[i - 1] + f[i - 2];
}
for (cin >> t; t; t--) {
cin >> l >> r, cout << (S(r) ^ S(l - 1)) << '\n';
}
return 0;
}
比较板子的同余最短路,模数为 \(min\{a_i,m\}\),答案为 \(min\{dis_i-k\}\)。
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 1e7 + 5, kMaxM = 3e7 + 5;
int t, n, m, a[kMaxN];
LL dis[kMaxM], ans = -1;
priority_queue<pair<LL, LL>, vector<pair<LL, LL>>, greater<pair<LL, LL>>> q;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
freopen("pear.in", "r", stdin);
freopen("pear.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i], m = min(m, a[i]);
}
fill(dis, dis + m, 1e18);
for (q.push({0, 0}), dis[0] = 0; !q.empty();) {
auto [w, v] = q.top();
q.pop();
if (dis[v] != w) {
continue;
}
for (int i = 1; i <= n; i++) {
if (dis[(v + a[i]) % m] > dis[v] + a[i]) {
dis[(v + a[i]) % m] = dis[v] + a[i], q.push({dis[(v + a[i]) % m], (v + a[i]) % m});
}
}
}
for (int i = 0; i < m; i++) {
ans = max(ans, dis[i] - m);
}
cout << ans << '\n';
return 0;
}