AtCoder Regular Contest 192 (Div. 2)
ARC192A ARC Arc
把需要的状态全记下来,然后直接 DP。
constexpr int N = 2e5 + 5;
bool f[N][3][3][4];
void slv() {
int n = Read<int>();
vector<int> A(n);
for (int i = 0; i < n; i ++) {
Read(A[i]);
}
auto chk = [&](int x, int y, int z) -> bool {
if (x == 0 && y == 1 && z == 2) {
return true;
}
if (x == 2 && y == 1 && z == 0) {
return true;
}
return false;
};
for (int A0 = 0; A0 < 3; A0 ++) {
for (int A1 = 0; A1 < 3; A1 ++) {
memset(f, false, sizeof f);
f[1][A0][A1][1] = true;
for (int i = 1; i + 1 < n; i ++) {
for (int x = 0; x < 3; x ++) {
for (int y = 0; y < 3; y ++) {
for (int o = 0; o < 4; o ++) {
if (f[i][x][y][o]) {
int k = o >> 1;
for (int z = 0; z < 3; z ++) {
bool can = chk(x, y, z);
if (can) {
if (i == 1) {
f[i + 1][y][z][3] = true;
} else {
f[i + 1][y][z][k << 1 | 1] = true;
}
} else if (o & 1) {
f[i + 1][y][z][k << 1 | A[i]] = true;
}
}
}
}
}
}
}
for (int x = 0; x < 3; x ++) {
for (int y = 0; y < 3; y ++) {
for (int o = 0; o < 4; o ++) {
if (f[n - 1][x][y][o]) {
bool can = true;
int k = o >> 1, m = o & 1;
can &= m || chk(x, y, A0);
can &= A[n - 1] || chk(x, y, A0) || chk(y, A0, A1);
can &= k || A[0] || chk(y, A0, A1);
if (can) {
Yes();
return;
}
}
}
}
}
}
}
No();
return;
}
ARC192B Fennec VS. Snuke 2
发现只有奇数的有用,然后打表。
怎么看见博弈论只会打表
void slv() {
int n = Read<int>();
int c1 = 0;
for (int i = 0; i < n; i ++) {
c1 += Read<int>() & 1;
}
if (n == 1) {
Puts("Fennec");
} else if (n == 2) {
Puts("Snuke");
} else if (n == 3) {
if (!c1) {
Puts("Snuke");
} else {
Puts("Fennec");
}
} else {
if (c1 & 1) {
Puts("Fennec");
} else {
Puts("Snuke");
}
}
return;
}
ARC192C Range Sums 2
由于 \(A_i > 0\),所以我们随便找一个点问一下它和其他每个点,这样最大的那个位置就一定是端点,这里花费 \(n - 1\) 次。
从这个端点再做一遍和上面相同的事情,那么我们问到的就是所有的前缀 / 后缀和,这样排序后就能得到另一个端点,还有正序或反序的 \(A\) 和 \(P\),花费 \(n - 2\) 次。
我们还需要知道两个端点分别是谁,由于 \(P_1 < P_2\),所以只需要问一下和 \(P_1, P_2\) 分别的区间和即可,这部分不消耗询问。
最后的问题是我们现在还没有确定 \(a_0, a_1\)(或 \(a_{n - 1}, a_n\))的值,这个只需要询问一下 \(a_0 + a_1 + a_2\) 和 \(a_1 +a_2\)(或 \(a_{n - 2} + a_{n - 1} + a_n\) 和 \(a_{n - 2} + a_{n - 1}\))即可,这部分消耗 \(1\) 次询问。
总询问数 \(2n - 2\)。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
int n;
cin >> n;
map<pair<int, int>, i64> mp;
auto qry = [&](int s, int t) {
if (s == t) {
return 0LL;
}
if (s > t) {
swap(s, t);
}
if (mp.contains({s, t})) {
return mp[{s, t}];
}
cout << "? " << s + 1 << ' ' << t + 1 << endl;
i64 sum; cin >> sum;
return mp[{s, t}] = sum;
};
auto ans = [&](vector<int> p, vector<int> a) {
cout << "! ";
for (auto x : p) {
cout << x + 1 << ' ';
}
for (auto x : a) {
cout << x << ' ';
}
cout << endl;
return;
};
int p0 = 0;
vector<int> p(n), a(n);
for (int i = 1; i < n; i ++) {
if (qry(0, i) > qry(0, p0)) {
p0 = i;
}
}
vector<pair<i64, int>> sum(n);
for (int i = 0; i < n; i ++) {
sum[i] = {qry(p0, i), i};
}
int p1 = max_element(sum.begin(), sum.end()) - sum.begin();
sort(sum.begin(), sum.end());
for (int i = n - 1; i > 1; i --) {
a[i] = sum[i].first - sum[i - 1].first;
}
a[0] = qry(p0, sum[2].second) - qry(sum[1].second, sum[2].second);
a[1] = qry(p0, sum[1].second) - a[0];
if (p0 == 0 || (p0 != 1 && qry(p0, 0) < qry(p0, 1))) {
p[p0] = 0, p[p1] = n - 1;
for (int i = 1; i + 1 < n; i ++) {
p[sum[i].second] = i;
}
} else {
p[p1] = 0, p[p0] = n - 1;
for (int i = 1; i + 1 < n; i ++) {
p[sum[i].second] = n - i - 1;
}
reverse(a.begin(), a.end());
}
ans(p, a);
return 0;
}
ARC192D Fraction Line
首先可以发现 \(\displaystyle f(x) = \frac{\operatorname{lcm}(P, Q)}{\gcd(P, Q)}\)。
每个质因子独立,对每个质因子分别计算答案,最后乘起来即可。
记质数 \(p\) 在 \(A_i\) 中的次数为 \(B_i\),那么我们要做的就是:
对于一个序列 \(C\),它的权值为 \(\displaystyle \prod_{1 \le i \le n} p^{C_i}\)。
求所有满足:
- \(\forall 1 \le i < n, \max(C_i, C_{i + 1}) - \min(C_i, C_{i + 1}) = B_i\)。
- \(\exists 1 \le i \le n, C_i = 0\)。
的序列 \(C\) 的权值之和。
这个问题可以简单地通过 \(O\big(n \sum B \big)\) 的 DP 解决。
那么总时间复杂度就是 \(O\big(n^2 \log \max A\big)\) 的。
void slv() {
int n = Read<int>();
vector<int> A(-- n);
for (int i = 0; i < n; i ++) {
Read(A[i]);
}
mint ans = mint::raw(1);
for (int p = 2; p <= 1000; p ++) {
if ([&]() -> bool {
for (int i = 2; i * i <= p; i ++) {
if (p % i == 0) {
return true;
}
}
return false;
}()) {
continue;
}
vector<int> B(n);
for (int i = 0; i < n; i ++) {
while (A[i] % p == 0) {
A[i] /= p, ++ B[i];
}
}
const int m = accumulate(B.begin(), B.end(), 0);
vector<array<mint, 2>> f(m + 1);
vector<mint> pw(m + 1);
pw[0] = mint::raw(1);
for (int i = 1; i <= m; i ++) {
pw[i] = pw[i - 1] * p;
}
for (int i = 0; i <= m; i ++) {
f[i][!i] = pw[i];
f[i][!!i] = mint::raw(0);
}
for (int i = 0; i < n; i ++) {
auto g = f;
fill(f.begin(), f.end(), array<mint, 2>{0, 0});
for (int j = 0; j <= m; j ++) {
mint g0 = 0, g1 = 0;
if (j - B[i] >= 0) {
g0 += g[j - B[i]][0];
g1 += g[j - B[i]][1];
}
if (B[i] && j + B[i] <= m) {
g0 += g[j + B[i]][0];
g1 += g[j + B[i]][1];
}
f[j][!j] += g0 * pw[j];
f[j][1] += g1 * pw[j];
}
}
mint res = 0;
for (int i = 0; i <= m; i ++) {
res += f[i][1];
}
ans *= res;
}
Write((int)ans, '\n');
return;
}
ARC192E Snuke's Kyoto Trip
这个题真的有 B 难吗,怎么这种唐题放 E 啊 /lh
感觉是史,开摆了。