RC-u1 热҈热҈热҈
思路
按题意模拟即可,统计所有可以喝到雪碧的天数,因为星期四无法喝到雪碧的天数。
复杂度
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)
代码实现
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n, w;
cin >> n >> w;
int cnt = 0, cnt1 = 0;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (x >= 35) {
if (w == 4)
cnt1++;
else
cnt++;
}
if (w == 7)
w = 1;
else
w++;
}
cout << cnt << ' ' << cnt1;
}
int main()
{
int T = 1;
// cin>>T;
while (T--) {
solve();
}
}
RC-u2 谁进线下了?
思路
同样也是按题意模拟,每读入第 i i i 个人的排名和杀敌数,根据排名计算出对应的得分,然后和杀敌数一起累加到数组下标为 i i i 的位置,最后对应输出即可。
复杂度
时空复杂度 O ( n ) O(n) O(n)
代码实现
#include <bits/stdc++.h>
using namespace std;
// 根据排名计算分数
int f(int x)
{
if (x == 1)
return 12;
if (x == 2)
return 9;
if (x == 3)
return 7;
if (x == 4)
return 5;
if (x == 5)
return 4;
if (x <= 7)
return 3;
if (x <= 10)
return 2;
if (x <= 15)
return 1;
return 0;
}
void solve()
{
int n;
cin >> n;
int val[25] = { 0 };
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 20; j++) {
int p, t;
cin >> p >> t;
val[j] += f(p) + t;
}
}
for (int i = 1; i <= 20; i++) {
cout << i << ' ' << val[i] << '\n';
}
}
int main()
{
int T = 1;
// cin>>T;
while (T--) {
solve();
}
}
RC-u3 暖炉与水豚
思路
首先,对暖炉周围的位置进行标记。
接着,遍历整个矩阵,看是否存在未被标记的位置,且该位置上有温暖的水豚
′
m
′
'm'
′m′。
如果存在的话说明该水豚周围存在暖炉,枚举水豚周围八个方向的位置
(
x
,
y
)
(x,y)
(x,y),如果
(
x
,
y
)
(x,y)
(x,y) 的位置为
′
.
′
'.'
′.′,且
(
x
,
y
)
(x,y)
(x,y) 周围八个方向不存在很冷的水豚
′
c
′
'c'
′c′,则该位置可以放置暖炉,
(
x
,
y
)
(x,y)
(x,y) 加入答案集合。
细节
1,遍历方向可以使用方向数组,即用数组记录下某个方向的偏移量。
2,检查八个方向的位置
(
x
,
y
)
(x,y)
(x,y),可能存在重复,可以直接存到
s
e
t
set
set 里面,这样去重且排好序了。
复杂度
时空复杂度 O ( n 2 ) O(n^2) O(n2)
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int n, m;
string g[N];
int st[N][N];
int dx[] = { -1, -1, -1, 0, 0, 1, 1, 1 }, dy[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> g[i];
g[i] = ' ' + g[i];
for (int j = 1; j <= m; j++) {
if (g[i][j] == 'm') {
// 标记暖炉周围八个方向
for (int k = 0; k < 8; k++) {
st[i + dx[k]][j + dy[k]] = 1;
}
}
}
}
set<array<int, 2>> ans;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// 没有被暖炉'm' 覆盖到的 'w'
if (!st[i][j] && g[i][j] == 'w') {
for (int k = 0; k < 8; k++) {
// 枚举周围的位置(x,y)
int x = i + dx[k], y = j + dy[k];
if (x < 1 || x > n || y < 1 || y > m || g[x][y] != '.')
continue;
int flag = 1;
for (int k1 = 0; k1 < 8; k1++) {
int xi = x + dx[k1], yi = y + dy[k1];
if (xi < 1 || xi > n || yi < 1 || yi > m)
continue;
flag &= g[xi][yi] != 'c';
// 检查(x,y) 周围是否有'c'
}
if (flag)
ans.insert({ x, y });
}
}
}
}
if (!ans.size()) {
cout << "Too cold!\n";
return;
}
for (auto it : ans) {
cout << it[0] << ' ' << it[1] << '\n';
}
}
int main()
{
int T = 1;
// cin>>T;
while (T--) {
solve();
}
}
RC-u4 章鱼图的判断
思路
感觉题意有些问题,里面想找的子图实际上是极大连通子图,即无向图中不连接在一起的连通块。
赛时想的有点复杂,但是注意到一些性质可以简单不少。
注意到章鱼图实际上是一个无向基环树,会满足以下条件:
1,满足边数恰好为点数;
2,删去环上的链后,环上点的度数最多为
2
2
2。
首先,对于每个连通块,可以统计该连通块的点数和连通块上点的度数和,因为度数和恰好为边数的两倍,所以就可以用点数,度数和判断是否满足条件 1 1 1。
找到连通块的所有点可以用 b f s bfs bfs 或者 d f s dfs dfs,遍历连通块时,要标记该连通块上遍历到的点已经遍历过,防止下次从连通块另一个点开始遍历连通块。
如果满足条件 1 1 1,则对该连通块进行删链,删链可以用 K a h n Kahn Kahn 算法(进行拓扑排序的算法),因为这里是无向图,所以最开始是将度数为 1 1 1 的点入队,然后当点 u u u 出队时,就把点 u u u 的相邻节点 v v v 的度数减 1 1 1(表示删去点 u u u),如果点 v v v 的度数为 1 1 1,则将点 v v v 入队。
为方便处理,在代码实现的时候,直接用 s e t set set 存领接表,度数看 s e t set set 的大小,然后点 u u u 出队时,把点 u u u 所有相邻节点 v v v 的领接表中删去。
K a h n Kahn Kahn 算法执行结束后,遍历连通块的所有点,看是否存在点的度数(领接表大小)大于 2 2 2,如果存在则该连通块不是章鱼子图。
如果连通块是章鱼子图,还需要统计环上的点数,这步可以在 K a h n Kahn Kahn 算法执行的之后一并完成。因为在最开始的 b f s / d f s bfs/dfs bfs/dfs 中,找出了连通块的点集 a l l all all,而 K a h n Kahn Kahn 算法遍历到的点都是链上的点,所以可以把 K a h n Kahn Kahn 算法遍历到的点从 a l l all all 中删去(为了删去的复杂度低, a l l all all 也用 s e t set set 存储),最后 a l l all all 的大小即为环上的点数。
最后根据要求输出即可,如果章鱼子图唯一则输出环的大小,否则输出章鱼子图的大小。
复杂度
s e t set set 插入删除的时间复杂度都是 O ( log n ) O(\log n) O(logn),因此总的时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),空间复杂度为 O ( n + m ) O(n+m) O(n+m)
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m;
int st[N];
// st[u] 表示该点是否遍历过
set<int> h[N];
int cnt, num;
// cnt为章鱼子图数量,num为章鱼子图环的大小
void bfs(int x)
{
int sum = 0;
set<int> all;
// all为连通块的点集
queue<int> q;
q.push(x);
st[x] = 1;
while (q.size()) {
int u = q.front();
q.pop();
all.insert(u);
sum += h[u].size();
for (int v : h[u]) {
if (!st[v]) {
st[v] = 1;
q.push(v);
}
}
}
// 点数恰好为边数
if (sum == all.size() * 2) {
cnt++;
for (int i : all) {
if (h[i].size() == 1) {
q.push(i);
}
}
while (q.size()) {
int u = q.front();
q.pop();
all.erase(u);
for (int v : h[u]) {
h[v].erase(u);
if (h[v].size() == 1) {
q.push(v);
}
}
h[u].clear();
}
for (int i : all) {
// 如果存在点度数大于2则不为章鱼子图
if (h[i].size() > 2)
return;
}
num = all.size();
}
}
void solve()
{
cin >> n >> m;
cnt = num = 0;
for (int i = 1; i <= n; i++) {
st[i] = 0;
h[i].clear();
}
while (m--) {
int a, b;
cin >> a >> b;
h[a].insert(b);
h[b].insert(a);
}
int ans = 0;
memset(st, 0, sizeof(st));
for (int i = 1; i <= n; i++) {
if (!st[i]) {
bfs(i);
}
}
if (cnt != 1) {
cout << "No " << cnt << '\n';
} else {
cout << "Yes " << num << '\n';
}
}
int main()
{
int T;
cin >> T;
while (T--) {
solve();
}
}
工作安排
思路
赛时没联想到该题可以类似背包进行 d p dp dp ,往暴力贪心方面想了。
令 f ( i , j ) f(i,j) f(i,j) 为安排前 i i i 个工作,截止时间恰好为 j j j 能取得的最大报酬。
注意到这里的状态表示涉及到截止时间的早晚问题,显然要先安排截止时间早的,所以要先按截止时间从小到大排序。
初始化:令所有状态默认为 0 0 0 即可,表示未获得任何报酬。
状态转移:
1,不安排第
i
i
i 个工作,则
f
(
i
,
j
)
=
f
(
i
−
1
,
j
)
f(i,j) = f(i-1,j)
f(i,j)=f(i−1,j)
2,安排第
i
i
i 个工作,则
f
(
i
,
j
)
=
f
(
i
−
1
,
j
−
t
)
+
p
f(i,j) = f(i-1,j-t)+p
f(i,j)=f(i−1,j−t)+p(
t
t
t 为花费时间,
p
p
p 为报酬),注意这种情况需要满足截止时间
j
j
j 不超过第
i
i
i 项工作的截止时间
d
d
d。
最后的答案即为 f ( n , x ) ( 0 ≤ x ≤ d n ) f(n,x)(0 \le x \le d_n) f(n,x)(0≤x≤dn) 取得的最大值。
细节
注意直接开二维数组记录,空间复杂度会超,所以需要用滚动数组优化空间复杂度,和 01 01 01 背包的优化方法是一样的,计算的时候倒序计算即可。
复杂度
时间复杂度 O ( n ∗ d ) O(n*d) O(n∗d),空间复杂度 O ( d ) O(d) O(d)
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
int n;
int f[N];
array<int, 3> a[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++) {
int t, d, p;
cin >> t >> d >> p;
a[i] = { d, t, p };
}
sort(a + 1, a + 1 + n);
memset(f, 0, sizeof(f));
for (int i = 1; i <= n; i++) {
int t = a[i][1], d = a[i][0], p = a[i][2];
for (int j = d; j >= t; j--) {
f[j] = max(f[j], f[j - t] + p);
}
}
int ans = 0;
for (int i = 0; i < N; i++) {
ans = max(ans, f[i]);
}
cout << ans << '\n';
}
int main()
{
int T;
cin >> T;
while (T--) {
solve();
}
}