Poisonous Cookies
答案是 b+min(c,a+b+1)b+\min(c,a+b+1)b+min(c,a+b+1) 。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
printf("%d\n", b + min(c, a + b + 1));
return 0;
}
Tree Burning
考虑最后一定存在一个分界点,在两个分界点之间反复横跳。枚举方向和分界点,前缀和计算答案即可。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int l, n;
scanf("%d %d", &l, &n);
vector<int> x(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &x[i]);
}
long long answer = 0;
for (int rotate = 0; rotate < 2; ++rotate) {
vector<int> p = x;
p.push_back(l);
for (int i = 0; i < n; ++i) {
p.push_back(l + x[i]);
}
vector<long long> sum(n * 2 + 1);
for (int i = 0; i < n * 2; ++i) {
sum[i + 1] = sum[i] + 2ll * i * (p[i + 1] - p[i]);
}
for (int i = 0; i <= n; ++i) {
int left = n - i, right = i;
int left_l = i, left_r = n;
int right_l = n, right_r = n + i;
long long result = 0;
if (left > right) {
int diff = left - right;
result += (long long) (p[left_r] - p[left_r - diff]) * (2 * right + 1);
left_r -= diff;
}
if (left < right) {
int diff = right - left;
result += (long long) (p[right_l + diff] - p[right_l]) * (2 * left);
right_l += diff;
}
result += (sum[left_r] - sum[left_l]) - (long long) (p[left_r] - p[left_l]) * (2 * left_l - 1);
result += (long long) (p[right_r] - p[right_l]) * (2 * right_r) - (sum[right_r] - sum[right_l]);
answer = max(answer, result);
}
for (int i = 0; i < n; ++i) {
x[i] = l - x[i];
}
reverse(x.begin(), x.end());
}
printf("%lld\n", answer);
return 0;
}
Coloring Torus
考虑 nnn 是偶数时,构造:ci,j=((i+j) mod n)+(i mod 2)×nc_{i,j} = ((i+j)\bmod n) + (i\bmod 2)\times nci,j=((i+j)modn)+(imod2)×n ,显然符合要求。
注意到将所有 i+ni+ni+n 换成 iii 也是合法的,所以可以构造出 [n,2n][n,2n][n,2n] 中的所有 kkk 。
特判 k=1k=1k=1 的情况,令 n=2⌈k4⌉n=2\lceil \frac{k}{4}\rceiln=2⌈4k⌉ 即可。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int k;
scanf("%d", &k);
if (k == 1) {
puts("1");
puts("1");
return 0;
}
int n = (k + 3) / 4 * 2;
printf("%d\n", n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int color = (i + j) % n;
if ((i & 1) && color + n < k) {
color += n;
}
printf("%d%c", color + 1, j == n - 1 ? '\n' : ' ');
}
}
return 0;
}
Inversion Sum
记 fi,jf_{i,j}fi,j 表示 ai>aja_i>a_jai>aj 的概率,转移时枚举与交换的位置有关的状态,只有 O(n)O(n)O(n) 个。
#include <bits/stdc++.h>
using namespace std;
const int md = 1e9 + 7;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline int mul(int x, int y) {
return (long long) x * y % md;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
vector<int> a(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
vector<vector<int>> f(n, vector<int> (n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
f[i][j] = a[i] > a[j];
}
}
int coef = 1;
while (m--) {
coef = mul(coef, 2);
int x, y;
scanf("%d %d", &x, &y);
--x;
--y;
f[x][y] = f[y][x] = mul(f[x][y] + f[y][x], md + 1 >> 1);
for (int i = 0; i < n; ++i) {
if (i != x && i != y) {
f[i][x] = f[i][y] = mul(f[i][x] + f[i][y], md + 1 >> 1);
f[x][i] = f[y][i] = mul(f[x][i] + f[y][i], md + 1 >> 1);
}
}
}
int answer = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
add(answer, f[i][j]);
}
}
printf("%d\n", mul(answer, coef));
return 0;
}
Less than 3
考虑在 010101 之间画一条红线, 101010 之间画一条蓝线,并在边界补充上无限的红蓝交替的线,那么一次操作就是将一条线移动一个位置(可以参考官方题解的图)。如果我们知道的线的对应关系,那么答案下界是至少移动的距离,同时可以证明这样的方案一定存在。一共只有 O(n)O(n)O(n) 种对应关系,枚举之后计算答案即可。
#include <bits/stdc++.h>
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
string s, t;
cin >> n >> s >> t;
if (n <= 2) {
int answer = 0;
for (int i = 0; i < n; ++i) {
if (s[i] != t[i]) {
++answer;
}
}
printf("%d\n", answer);
return 0;
}
vector<pair<int, int>> diff_s, diff_t;
for (int i = 0; i < n - 1; ++i) {
if (s[i] != s[i + 1]) {
diff_s.emplace_back(i, s[i] - '0');
}
if (t[i] != t[i + 1]) {
diff_t.emplace_back(i, t[i] - '0');
}
}
int answer = INT_MAX;
auto solve = [&](vector<pair<int, int>> a, vector<pair<int, int>> b) {
if (a.size() > b.size()) {
swap(a, b);
}
reverse(a.begin(), a.end());
while (a.size() < b.size()) {
a.emplace_back(-1, !a.back().second);
}
reverse(a.begin(), a.end());
if (a.back().second == b.back().second) {
int result = 0;
for (int i = 0; i < a.size(); ++i) {
result += abs(a[i].first - b[i].first);
}
answer = min(answer, result);
}
};
for (int rotate = 0; rotate < 2; ++rotate) {
vector<pair<int, int>> new_diff_t = diff_t;
for (int i = 0; i <= n; ++i) {
solve(diff_s, new_diff_t);
new_diff_t.emplace_back(n - 1, !new_diff_t.back().second);
}
swap(diff_s, diff_t);
}
printf("%d\n", answer);
return 0;
}
Permutation and Minimum
考虑一对 (A2i−1,A2i)(A_{2i-1}, A_{2i})(A2i−1,A2i) ,如果它们都有值了就直接扔掉,剩下的只有两种:(−1,−1)(-1, -1)(−1,−1) 和 (−1,x)(-1, x)(−1,x) 。对于 (−1,−1)(-1, -1)(−1,−1) ,我们忽略它们的位置关系,最后答案乘上其个数的阶乘。
考虑从大到小填数,记 f(i,j,k)f(i,j,k)f(i,j,k) 表示当前考虑到 iii ,有 jjj 个 −1-1−1 没有匹配,有 kkk 个 xxx 没有匹配,考虑转移:
-
如果 iii 是某个 xxx :
-
不匹配,转移到 f(i−1,j,k+1)f(i-1,j,k+1)f(i−1,j,k+1)
-
匹配一个 −1-1−1 ,转移到 f(i−1,j−1,k)f(i-1,j-1,k)f(i−1,j−1,k)
-
-
如果 iii 不是某个 xxx :
- 不匹配,转移到 f(i−1,j+1,k)f(i-1,j+1,k)f(i−1,j+1,k)
- 匹配一个 −1-1−1 ,因为是无序的所以直接转移到 f(i−1,j−1,k)f(i-1,j-1,k)f(i−1,j−1,k)
- 匹配一个 xxx ,因为 xxx 的位置有关所以有 kkk 种方案转移到 f(i−1,j,k−1)f(i-1,j,k-1)f(i−1,j,k−1)
#include <bits/stdc++.h>
using namespace std;
const int md = 1e9 + 7;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline int mul(int x, int y) {
return (long long) x * y % md;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
vector<bool> used(n * 2);
vector<bool> single(n * 2);
int free = 0;
for (int i = 0; i < n; ++i) {
int x, y;
scanf("%d %d", &x, &y);
if (~x) {
--x;
}
if (~y) {
--y;
}
if (~max(x, y)) {
if (~min(x, y)) {
used[x] = used[y] = true;
} else {
single[max(x, y)] = true;
}
} else {
++free;
}
}
vector<vector<int>> dp(n + 1, vector<int> (n * 2 + 1));
dp[0][0] = 1;
for (int i = n * 2 - 1; ~i; --i) {
if (!used[i]) {
vector<vector<int>> new_dp(n + 1, vector<int> (n * 2 + 1));
for (int j = 0; j <= n; ++j) {
for (int k = 0; k <= n * 2; ++k) {
if (dp[j][k]) {
if (single[i]) {
add(new_dp[j + 1][k], dp[j][k]);
if (k) {
add(new_dp[j][k - 1], dp[j][k]);
}
} else {
add(new_dp[j][k + 1], dp[j][k]);
if (j) {
add(new_dp[j - 1][k], mul(j, dp[j][k]));
}
if (k) {
add(new_dp[j][k - 1], dp[j][k]);
}
}
}
}
}
swap(dp, new_dp);
}
}
int answer = dp[0][0];
for (int i = 1; i <= free; ++i) {
answer = mul(answer, i);
}
printf("%d\n", answer);
return 0;
}