C - King’s Summit

  • 给定一个n * n的矩阵,每个方格上有一个人,每回合所有人可以在离自己最近的3 * 3矩阵内活动,问最少几个回合后,所有人在一个格子上
  • 容易想到,两点间的距离实际上是

$$
d(i, j) = max(|x_i - x_j|, |y_i - y_j|)
$$

  • 因此我们其实要找的是所有点中x或y坐标最大的差值d,$\lceil d \rceil$就是最小回合数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>

using namespace std;

const int N = 1e6+10;
struct Point
{
int x, y;
} p[N];

bool cmp1(const Point &a, const Point &b) {
return a.x < b.x;
}

bool cmp2(const Point &a, const Point &b) {
return a.y < b.y;
}

int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> p[i].x >> p[i].y;
}
sort(p + 1, p + n + 1, cmp1);
int max_dist = p[n].x - p[1].x;
sort(p + 1, p + n + 1, cmp2);
max_dist = max(max_dist, p[n].y - p[1].y);

int res = max_dist % 2 == 0 ? max_dist / 2 : max_dist / 2 + 1;
cout << res << endl;
return 0;
}

D - Substr Swap

  • 给定两个等长的字符串s1,s2,共有n次交换,每次交换s1[l-r]和s2[l-r],问n次交换的s1

  • 可以用cnt[i]记录位置i交换了多少次,最后奇偶性判断就可以了

  • 对区间加可以用差分数组维护,每次区间加从$O(r - l)$优化到$O(1)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>

using namespace std;
const int N = 5e5+10;

int n, m;
string s, t;

// 差分数组 sub[i] = cnt[i] - cnt[i - 1], cnt[0] = 0
int sub[N];
int cnt[N];

int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

cin >> n >> m;
cin >> s >> t;
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
sub[l]++;
sub[r + 1]--;
}
for (int i = 1; i <= n; i++) {
cnt[i] = cnt[i - 1] + sub[i];
}

for (int i = 1; i <= n; i++) {
if (cnt[i] % 2 == 1) {
s[i - 1] = t[i - 1];
}
}
cout << s << endl;


return 0;
}

E - Subarray Sum Divisibility

  • dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<bits/stdc++.h>

using namespace std;
const int N = 500+10;
const int INF = 1e9;
int n, m, l;
int a[N];
// dp[i][j]代表a[1] to a[i] = j mod m 的步数
// ans = dp[L][0]
int dp[N][N];
// c[i][j] 代表把a[i + kL]-> j mod m的总花费
int c[N][N];

int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

cin >> n >> m >> l;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= l; i++) {
for (int j = 0; j < m; j++) {
for (int p = i; p <= n; p += l) {
// a[p] -> j 总花费
c[i][j] += (j - a[p] + m) % m;
}
}
}
fill(dp[0], dp[0] + N * N, INF);
dp[0][0] = 0;
for (int i = 1; i <= l; i++) {
for (int j = 0; j < m; j++) {
for (int k = 0; k < m; k++) {
dp[i][j] = min(dp[i][j], dp[i - 1][(j - k + m) % m] + c[i][k]);
}
}
}
cout << dp[l][0] << endl;

return 0;
}

F - All Included

G - Count Simple Paths 2

  • 最短路 dfs 剪枝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<bits/stdc++.h>

using namespace std;
typedef pair<int, int> PII;
const int N = 2e5+10;
int n, m;
set<PII> g[N];
int cnt[N] = {0};
bool vis[N] = {false};

void dfs(int u, int l) {
if (u == n) {
cnt[l]++;
return;
}
vis[u] = true;
for (auto [v, w] : g[u]) {
if (!vis[v]) {
dfs(v, l + w);
}
}
vis[u] = false;
}

int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].insert({v, 1});
g[v].insert({u, 1});
}
// 删去度为1的点
queue<int> q;
for (int i = 2; i <= n - 1; i++) {
if (g[i].size() == 1) q.push(i);
}
while (!q.empty()) {
int u = q.front();q.pop();
int to = g[u].begin()->first;
g[to].erase({u, 1});
if (to != 1 && to != n && g[to].size() == 1) q.push(to);
}
// 合并度为2的点
for (int i = 2; i <= n - 1; i++) {
if (g[i].size() == 2) {
auto [u, w1] = *g[i].begin();
auto [v, w2] = *next(g[i].begin());
g[u].erase(g[u].find({i, w1}));
g[v].erase(g[v].find({i, w2}));
g[u].insert({v, w1 + w2});
g[v].insert({u, w1 + w2});
}
}
dfs(1, 0);
for (int i = 1; i <= n - 1; i++) {
if (i > 1) cout << " ";
cout << cnt[i];
}

return 0;
}