从这里开始
我又不太会 div 1 A? 我菜爆了。。。
Problem A Cut and Paste
暴力模拟一下。
Code
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 1e6 + 5;
const int Mod = 1e9 + 7; int T;
int x;
int len;
char s[N]; int paste(int s1, int t1, int s2) {
int i = s2;
for (i = s2; i <= x && i - s2 + s1 <= t1; i++)
s[i] = s[i - s2 + s1];
return i;
} void solve() {
scanf("%d", &x);
scanf("%s", s + 1);
len = strlen(s + 1);
int rlen = len;
for (int i = 1; i <= x; i++) {
int t = s[i] - '0' - 1;
len = ((i + (len - i) * 1ll * (t + 1)) % Mod + Mod) % Mod;
int qaq = rlen;
while (t--)
rlen = paste(i + 1, qaq, rlen + 1) - 1;
}
printf("%d\n", len);
} int main() {
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
Problem B Beingawesomeism
不难注意到答案不会超过 4.
- 答案为 0,这个很 trivial
- 答案小于等于 1 显然是存在一个边界被完全覆盖
- 答案小于等于 2,存在一个 A 在角落或者完整的一行或一列为 A
- 答案小于等于 3,存在 1 个 A 在边界上
- 剩下的情况答案为 4
Code
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 66; int T, n, m;
char s[N][N]; int count(int x1, int y1, int x2, int y2) {
int x = 0;
for (int i = x1; i <= x2; i++) {
for (int j = y1; j <= y2; j++) {
x += s[i][j] == 'A';
}
}
return x;
} void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", s[i] + 1);
}
int c = count(1, 1, n, m);
if (!c) {
puts("MORTAL");
return;
}
if ((c == n * m)) {
puts("0");
return;
}
boolean havec = (s[1][1] == 'A' || s[n][1] == 'A' || s[1][m] == 'A' || s[n][m] == 'A');
int L = count(1, 1, n, 1);
int R = count(1, m, n, m);
if (L == n || R == n) {
puts("1");
return;
}
int U = count(1, 1, 1, m);
int D = count(n, 1, n, m);
if (U == m || D == m) {
puts("1");
return;
}
if (havec) {
puts("2");
return;
}
for (int i = 1; i <= n; i++) {
if (count(i, 1, i, m) == m) {
puts("2");
return;
}
}
for (int i = 1; i <= m; i++) {
if (count(1, i, n, i) == n) {
puts("2");
return;
}
}
if (L + R + U + D) {
puts("3");
return;
}
puts("4");
} int main() {
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
Problem C Jeremy Bearimy
最大的话,显然以重心为根,答案为每个点的深度和
最小的话,显然每个点的子树内至多有 1 个未匹配点,dp 即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 6e5 + 5; #define ll long long
#define pii pair<int, int> const ll llf = (signed ll) (~0ull >> 3); template <typename T>
boolean vmin(T& a, T b) {
if (a > b) {
a = b;
return true;
}
return false;
} int T;
int n, n2;
int sz[N];
vector<pii> G[N]; int get_sz(int p, int fa) {
sz[p] = 1;
for (auto E : G[p]) {
int e = E.first;
if (e == fa)
continue;
sz[p] += get_sz(e, p);
}
return sz[p];
} int get_g(int p, int fa) {
for (auto E : G[p]) {
int e = E.first;
if (e == fa)
continue;
if (sz[e] > n) {
return get_g(e, p);
}
}
return p;
} ll dep[N];
void dfs(int p, int fa) {
for (auto E : G[p]) {
int e = E.first;
int w = E.second;
if (e == fa)
continue;
dep[e] = dep[p] + w;
dfs(e, p);
}
} ll f[N][2];
void dp(int p, int fa) {
static ll g[2];
f[p][0] = llf, f[p][1] = 0;
for (auto E : G[p]) {
int e = E.first;
int w = E.second;
if (e == fa)
continue;
dp(e, p);
g[0] = g[1] = llf;
vmin(g[0], f[p][0] + f[e][0]);
vmin(g[0], f[p][1] + f[e][1] + w);
vmin(g[1], f[p][0] + f[e][1] + w);
vmin(g[1], f[p][1] + f[e][0]);
f[p][0] = g[0];
f[p][1] = g[1];
}
} void solve() {
scanf("%d", &n);
n2 = n << 1;
for (int i = 1; i <= (n << 1); i++) {
G[i].clear();
}
for (int i = 1, u, v, t; i < n2; i++) {
scanf("%d%d%d", &u, &v, &t);
G[u].emplace_back(v, t);
G[v].emplace_back(u, t);
}
get_sz(1, 0);
int g = get_g(1, 0);
dep[g] = 0;
dfs(g, 0);
ll ansmx = 0;
for (int i = 1; i <= n2; i++) {
ansmx += dep[i];
}
dp(g, 0);
printf("%lld %lld\n", f[g][0], ansmx);
} int main() {
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
Problem D Miss Punyverse
考虑如果子树内留下的决策不是已有的合法划分最多的一个,至多使答案增加 1,但这里会减少 1,因此子树内决策只用保留合法划分最多,且未结束划分的一块的和最大。
然后 dp 即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long #define pii pair<int, ll> pii operator + (pii a, pii b) {
return pii(a.first + b.first, a.second + b.second);
} const int N = 3005; int T, n, m;
int sz[N];
pii f[N][N];
int a[N], b[N];
vector<int> G[N]; pii work(pii x) {
x.first += x.second > 0;
x.second = 0;
return x;
} void dfs(int p, int fa) {
static pii g[N];
for (int i = 0; i <= m; i++)
f[p][i] = pii(-N, 0);
f[p][0] = pii(0, 0);
sz[p] = 0;
for (auto e : G[p]) {
if (e == fa)
continue;
dfs(e, p);
for (int i = 0; i <= sz[p] + sz[e] && i <= m; i++)
g[i] = pii(-N, 0);
for (int i = 0; i <= sz[p]; i++) {
for (int j = 0; j < sz[e] && i + j <= m; j++) {
g[i + j] = max(g[i + j], f[p][i] + f[e][j]);
if (j < m)
g[i + j + 1] = max(g[i + j + 1], f[p][i] + work(f[e][j]));
}
}
for (int i = 0; i <= sz[p] + sz[e] && i <= m; i++)
f[p][i] = g[i];
sz[p] += sz[e];
}
++sz[p];
for (int i = 0; i < sz[p]; i++) {
f[p][i].second += a[p] - b[p];
}
} void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", b + i);
}
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; i++)
G[i].clear();
for (int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
int ans = work(f[1][m - 1]).first;
printf("%d\n", ans);
} int main() {
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
Problem E Kirchhoff's Current Loss
这个 E 感觉挺简单的,可惜我没时间做了,sad.....
考虑 $n$ 个电阻串联,答案为 $r$,这个很显然
考虑 $n$ 个电阻并联,答案为 $n^2r$,证明考虑用均值不等式归纳。
简单归纳一下可以发现,最终一定是等效于 $k$ 个电阻并联。
然后 dp 即可。
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 2e5 + 5; int T;
int n, m, r;
char s[1000000];
boolean ispar[N];
vector<int> G[N]; int newnode() {
++n;
G[n].clear();
ispar[n] = false;
return n;
} int id[N];
int build(char* &s) {
int p = newnode();
while (true) {
while (*s == ' ')
s++;
if (!*s || *s == ')')
return p;
if (*s == 'P') {
ispar[p] = true;
} else if (*s == 'S') {
ispar[p] = false;
} else if (*s == '(') {
G[p].push_back(build(++s));
} else if (*s == '*') {
G[p].push_back(newnode());
id[n] = ++m;
}
s++;
}
return p;
} int f[N], g[N], R[N];
void dfs(int p) {
if (G[p].empty()) {
f[p] = 1;
return;
}
if (!ispar[p]) {
f[p] = 1e9;
g[p] = -1;
for (auto e : G[p]) {
dfs(e);
if (f[e] < f[p]) {
f[p] = f[e];
g[p] = e;
}
}
} else {
f[p] = 0;
for (auto e : G[p]) {
dfs(e);
f[p] += f[e];
}
}
} void dfs1(int p) {
if (G[p].empty()) {
R[id[p]] = 1;
return;
}
if (ispar[p]) {
for (auto e : G[p])
dfs1(e);
} else {
dfs1(g[p]);
}
} int main() {
scanf("%d", &T);
while (T--) {
n = m = 0;
scanf("%d", &r);
gets(s);
char* tmp = s;
build(tmp);
dfs(1);
long long v = 1ll * r * f[1];
for (int i = 1; i <= m; i++) {
R[i] = 0;
}
dfs1(1);
printf("REVOLTING");
for (int i = 1; i <= m; i++)
printf(" %lld", R[i] * v);
putchar('\n');
}
return 0;
}
Problem F Intergalactic Sliding Puzzle
考虑按顺时针的构成的环排列,不考虑空位置。
注意到大环不会影响环排列,而空位置经过中间的隔板会做一个长度为 $2k + 1$ 的循环移位。
不难发现必要条件是排列的逆序对个数位偶数个,因为这些循环移位均不会改变逆序对奇偶性。
通过打表(或者阅读题解)可以构造把连续 3 个数循环位移的方案。
然后简单构造一下就行了。
Code
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 128; string operator * (string a, int t) {
string b = "";
for (int i = 0; i < t; i++)
b += a;
return b;
}
ostream& operator << (ostream& os, vector<int> p) {
for (auto x : p)
os << x << " ";
os << '\n';
return os;
} string sl("l"), sr("r"), su("u"), sd("d"); int T, k, L, n;
int x, y;
vector<int> grid[2];
vector<int> perm; void solve() {
cin >> k;
L = 2 * k + 1;
n = 4 * k + 1;
grid[0].resize(L);
grid[1].resize(L);
string _;
for (int i = 0; i < L; i++) {
cin >> _;
if (_[0] == 'E') {
grid[0][i] = -1;
x = 0, y = i;
} else {
grid[0][i] = stoi(_);
}
}
for (int i = 0; i < L; i++) {
cin >> _;
if (_[0] == 'E') {
grid[1][i] = -1;
x = 1, y = i;
} else {
grid[1][i] = stoi(_);
}
}
string ans = "";
while (x != 0 || y != k) {
if (x == 0) {
if (y < k) {
ans += 'r';
swap(grid[x][y], grid[x][y + 1]);
y++;
} else {
ans += 'l';
swap(grid[x][y], grid[x][y - 1]);
y--;
}
} else {
if (!y) {
ans += 'u';
swap(grid[x][y], grid[x - 1][y]);
x--;
} else {
ans += 'l';
swap(grid[x][y], grid[x][y - 1]);
y--;
}
}
}
perm.clear();
reverse(grid[1].begin(), grid[1].end());
for (auto x : grid[0])
if (x > 0)
perm.push_back(x);
for (auto x : grid[1])
if (x > 0)
perm.push_back(x);
for (auto &x : perm)
if (x > L)
x = n - (x - L) + 1;
int inv = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (perm[i] > perm[j]) {
inv ^= 1;
}
}
}
if (inv) {
cout << ("SURGERY FAILED") << '\n';
return;
}
auto rotateL = [&] () {
rotate(perm.begin(), perm.begin() + 1, perm.end());
ans += "A";
};
auto rotateR = [&] () {
rotate(perm.begin(), perm.end() - 1, perm.end());
ans += "B";
};
auto shift3 = [&] () {
swap(perm[0], perm[2]);
swap(perm[1], perm[2]);
ans += "S";
};
string A = sr * k + sd + sl * (L - 1) + su + sr * k;
string B = sl * k + sd + sr * (L - 1) + su + sl * k;
string C = sr * k + sd + sl * k + su;
string D = sd + sr * k + su + sl * k;
string S = string("B") * (k - 1) + "CBCADD" + string("A") * (k - 1);
while (perm[0] != 1)
rotateR();
for (int i = 2; i <= n - 2; i++) {
int d = -1;
while (perm[0] != i)
d++, rotateL();
if (d & 1) {
if (perm[1] == 1) {
rotateR(), rotateR();
shift3(), shift3();
d--;
rotateL();
} else if (perm[2] == 1) {
rotateR();
shift3();
d++;
rotateL();
rotateL();
} else {
shift3();
rotateL();
d++;
}
}
while (d) {
rotateR(), rotateR();
shift3();
d -= 2;
}
}
while (perm[0] != 1)
rotateR();
ans += sr * k + sd;
cout << "SURGERY COMPLETE\n";
cout << ans << '\n';
cout << "A " << A << '\n';
cout << "B " << B << '\n';
cout << "C " << C << '\n';
cout << "D " << D << '\n';
cout << "S " << S << '\n';
cout << "DONE\n";
} int main() {
// freopen("a.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> T;
while (T--) {
solve();
}
return 0;
}