2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛
A. A Xor B Problem
思路
记录每个数出现的次数,结果为每个数出现的次数的平方和
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
void solve()
{
int n;
cin >> n;
vector<int> cnt(N);
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
cnt[x]++;
}
ll ans = 0;
for (int i = 0; i < N; i++)
ans += 1LL * cnt[i] * cnt[i];
cout << ans;
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
B. 吃苹果
思路
将每天按晚上吃和白天吃的愉悦值之差进行排序,选前 \(k\) 个晚上吃,其他的白天吃
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n, k;
cin >> n >> k;
vector<pair<int, int>> a(n);
for (int i = 0; i < n; i++)
cin >> a[i].first >> a[i].second;
sort(a.begin(), a.end(), [](pair<int, int> &x, pair<int, int> &y)
{ return x.second - x.first > y.second - y.first; });
ll ans = 0;
for (int i = 0; i < n; i++)
{
if (i < k)
ans += a[i].second;
else
ans += a[i].first;
}
cout << ans;
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
C. n皇后问题
思路
每个皇后的攻击范围为
- 行号相同
- 列号相同
- 行号和列号的差相同
- 行号和列号的和相同
查询之前是否出现过即可
使用数组记录需考虑下标为负的情况
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n, t;
cin >> n >> t;
unordered_set<int> row, col, diag1, diag2;
for (int i = 0; i < t; i++)
{
int x, y;
cin >> x >> y;
if (row.count(x) || col.count(y) || diag1.count(x - y) || diag2.count(x + y))
{
cout << "No" << '\n';
continue;
}
row.insert(x);
col.insert(y);
diag1.insert(x - y);
diag2.insert(x + y);
cout << "Yes" << '\n';
}
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
D. 分苹果
思路
高中线性规划问题,已知苹果不会在线的上,所以将苹果的坐标 \((x,y)\) 代入直线方程 \(ax+by+c = 0\) 中
\(ax+by+c>0\) 和 \(ax+by+c<0\) 表示苹果在线的两侧
通过 01串
表示苹果在哪一块区域
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n;
cin >> n;
vector<tuple<int, int, int>> v(2);
for (int i = 0; i < 2; i++)
{
int a, b, c;
cin >> a >> b >> c;
v[i] = {a, b, c};
}
vector<int> ans(4);
for (int i = 0; i < n; i++)
{
ll x, y;
cin >> x >> y;
int flag = 0;
for (int j = 0; j < 2; j++)
{
auto [a, b, c] = v[j];
ll d = a * x + b * y + c;
if (d > 0)
flag |= 1 << j;
}
ans[flag]++;
}
sort(ans.begin(), ans.end());
for (int i = 0; i < 4; i++)
{
cout << ans[i] << ' ';
}
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
E. 完型填空
思路
动态规划问题
dp[i][j][k][l]
表示选择了 \(A,B,C,D\) 四个选项分别选择了 \(i,j,k,l\) 次的最大期望
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[26][26][26][26];
void solve()
{
int n;
cin >> n;
vector<array<int, 4>> v(n + 1);
for (int i = 1; i <= n; i++)
cin >> v[i][0] >> v[i][1] >> v[i][2] >> v[i][3];
for (int i = 0; i <= n / 4; i++)
{
for (int j = 0; j <= n / 4; j++)
{
for (int k = 0; k <= n / 4; k++)
{
for (int l = 0; l <= n / 4; l++)
{
auto [a, b, c, d] = v[i + j + k + l];
if (i != 0)
dp[i][j][k][l] = max(dp[i][j][k][l], dp[i - 1][j][k][l] + a);
if (j != 0)
dp[i][j][k][l] = max(dp[i][j][k][l], dp[i][j - 1][k][l] + b);
if (k != 0)
dp[i][j][k][l] = max(dp[i][j][k][l], dp[i][j][k - 1][l] + c);
if (l != 0)
dp[i][j][k][l] = max(dp[i][j][k][l], dp[i][j][k][l - 1] + d);
}
}
}
}
cout << dp[n / 4][n / 4][n / 4][n / 4];
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
F. 坐火车
思路
通过 \(BFS\) 计算出从 \(1\) 到任何城市所需经历的最少城市数量
再使用 \(dijkstra\) 在经历最少城市数量的前提下寻找最短路,即对于 \(u \to v\),需要满足 \(d[v] = d[u] + 1\),其中 \(d[i]\) 表示从 \(1\) 到 \(i\) 需要经历的最少城市数量
Code
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<pair<int, ll>>> g(n + 1);
for (int i = 0; i < m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({v, w});
g[v].push_back({u, w});
}
vector<int> d(n + 1);
function<void()> bfs = [&]()
{
queue<int> q;
q.push(1);
vector<bool> vis(n + 1);
vis[1] = true;
d[1] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (auto [v, w] : g[u])
{
if (vis[v])
continue;
vis[v] = true;
d[v] = d[u] + 1;
q.push(v);
}
}
};
bfs();
vector<ll> dis(n + 1, 0x3f3f3f3f3f3f3f3f);
function<void()> dijkstra = [&]()
{
priority_queue<int> q;
q.push(n);
vector<bool> vis(n + 1);
dis[n] = 0;
while (!q.empty())
{
int u = q.top();
q.pop();
if (vis[u])
continue;
vis[u] = true;
for (auto [v, w] : g[u])
{
if (d[v] != d[u] - 1)
continue;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push(v);
}
}
}
};
dijkstra();
cout << d[n] << ' ' << dis[1];
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
G. A Xor B Problem again
思路
如果两个数 \(a,\ b\) 满足 \(a\oplus b = a + b\),则这两个数在二进制表示下没有位同时为 \(1\)
对于一个数 \(10110_{(2)}\) 可知满足条件的数有 \(01001_{(2)},\ 01000_{(2)},\ 00001_{(2)}\),而后面两个数都是前一个数的子集
故我们只需找出 \(11111_{(2)} \oplus 10110_{(2)}\) 的子集的大小即可
Code
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n;
cin >> n;
vector<int> dp(200000);
vector<int> a(n);
for (int i = 0; i < n; i++)
{
cin >> a[i];
dp[a[i]]++;
}
for (int i = 0; i < 17; i++)
{
for (int j = 0; j < (1 << 17); j++)
{
if (j & (1 << i))
dp[j] += dp[j ^ (1 << i)];
}
}
ll ans = 0;
for (int i = 0; i < n; i++)
{
ans += dp[((1 << 17) - 1) ^ a[i]];
}
cout << ans;
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
H. 摘苹果
思路
线段树
- \(num\) 表示当前节点有多少苹果
- \(cnt\) 表示当前节点有多少课树的苹果数量小于 \(100\)
- \(flag\) 表示当前节点下没有可以采摘的苹果数
Code
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct node
{
ll num, cnt;
bool flag;
} seg[N * 4];
vector<int> a(N);
void update(int id)
{
seg[id].num = seg[id * 2].num + seg[id * 2 + 1].num;
seg[id].cnt = seg[id * 2].cnt + seg[id * 2 + 1].cnt;
seg[id].flag = seg[id * 2].flag & seg[id * 2 + 1].flag;
}
void build(int id, int l, int r)
{
if (l == r)
{
seg[id].num = a[l];
if (seg[id].num < 100)
seg[id].cnt = 1;
if (seg[id].num < 10)
seg[id].flag = 1;
return;
}
int mid = (l + r) / 2;
build(id * 2, l, mid);
build(id * 2 + 1, mid + 1, r);
update(id);
}
void modify(int id, int l, int r, int ql, int qr)
{
if (seg[id].flag)
return;
if (l == r)
{
seg[id].num = seg[id].num - (seg[id].num + 2) / 3;
if (seg[id].num < 100)
seg[id].cnt = 1;
if (seg[id].num < 10)
seg[id].flag = 1;
return;
}
int mid = (l + r) / 2;
if (qr <= mid)
modify(id * 2, l, mid, ql, qr);
else if (ql > mid)
modify(id * 2 + 1, mid + 1, r, ql, qr);
else
{
modify(id * 2, l, mid, ql, mid);
modify(id * 2 + 1, mid + 1, r, mid + 1, qr);
}
update(id);
}
int querycnt(int id, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return seg[id].cnt;
int mid = (l + r) / 2;
if (qr <= mid)
return querycnt(id * 2, l, mid, ql, qr);
else if (ql > mid)
return querycnt(id * 2 + 1, mid + 1, r, ql, qr);
else
return querycnt(id * 2, l, mid, ql, mid) + querycnt(id * 2 + 1, mid + 1, r, mid + 1, qr);
}
ll querynum(int id, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return seg[id].num;
int mid = (l + r) / 2;
if (qr <= mid)
return querynum(id * 2, l, mid, ql, qr);
else if (ql > mid)
return querynum(id * 2 + 1, mid + 1, r, ql, qr);
else
return querynum(id * 2, l, mid, ql, mid) + querynum(id * 2 + 1, mid + 1, r, mid + 1, qr);
}
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
while (m--)
{
int op, l, r;
cin >> op >> l >> r;
if (op == 1)
modify(1, 1, n, l, r);
else if (op == 2)
cout << querycnt(1, 1, n, l, r) << endl;
else if (op == 3)
cout << querynum(1, 1, n, l, r) << endl;
}
}
int main()
{
cin.tie(0)->ios::sync_with_stdio(false);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛
http://xiaowhang.github.io/archives/3300329301/