[Kick Start] 2021 Round A
题目:2021 Round-A .
K-Goodness String
签到题,计算当前字符串的 K-Goodness Score ,然后与给出的 K 做差即可。
#include <iostream>
#include <string>
using namespace std;
int cnt = 1;
int solve(const string &s, int n, int k)
{
int cur = 0;
for (int i = 0; i < n / 2; i++) cur += s[i] != (s[n - i - 1]);
return abs(k - cur);
}
int main()
{
int t, n, k;
string str;
cin >> t;
while (t--)
{
cin >> n >> k;
cin.ignore();
cin >> str;
cin.ignore();
printf("Case #%d: %d\n", cnt++, solve(str, n, k));
}
}
L Shaped Plots
L 字要求长边的长度是短边的 2 倍。短边长度至少为 2 ,长边长度至少为 4 。
枚举每个 matrix[i, j] == 1
的点(把该位置视为 L 的拐点)求出其上下左右四个方向的 1 的长度,通过 {up, down, left, right}
4 个变量记录。
然后对于 4 个方向,把该方向作为短边尝试一次,计算以该方向作为短边的 L 的个数。
以下面输入为例子:
1 0 0 0
1 0 0 1
1 1 1 1
1 0 1 0
1 0 1 0
1 1 1 0
在位置 (2, 2)
上,其 4 个方向的 1 的长度为 {up=1, down=4, left=3, right=1}
,那么:
up = 1
,该方向不能为短边。down = 4
,以该方向为短边时,那么长边必然是left
或者right
。 在down
方向上,短边长度可以为 2, 3, 4, 但left, right
作为长边均不满「长边长度至少 4 的要求」。left = 3
,以该方向作为短边,短边长度可以为 2 或者 3,当为 2 时,可以与down
组成 1 个 L 字。right = 2
,以该方向作为短边,长度为 2 ,可以与down
组成 1 个 L 字。
因此在位置 (2, 2)
上共有 2 个 L 字。
时间复杂度 \(O(n^3)\) .
#include <iostream>
#include <vector>
#include <array>
using namespace std;
#define MAXN 1001
int nums[MAXN][MAXN] = {{0}};
int cnt = 1;
int rows, cols;
array<int, 4> getFourLength(int i, int j)
{
int up, down, left, right;
up = down = i, left = right = j;
while (up >= 0 && nums[up][j]) up--;
while (down < rows && nums[down][j]) down++;
while (left >= 0 && nums[i][left]) left--;
while (right < cols && nums[i][right]) right++;
return array<int, 4>({i - up, down - i, j - left, right - j});
}
int solve()
{
int ans = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (nums[i][j] == 0) continue;
auto [up, down, left, right] = getFourLength(i, j);
auto calc = [&ans](int shortedge, int longedge1, int longedge2) {
for (int d = 2; d <= shortedge; d++)
ans += (longedge1 >= 2*d), ans += (longedge2 >= 2*d);
};
calc(up, left, right), calc(down, left, right);
calc(left, up, down), calc(right, up, down);
}
}
return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> rows >> cols;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
cin >> nums[i][j];
printf("Case #%d: %d\n", cnt++, solve());
}
}
Rabbit House
题目的意思就是说,每个「极高点」(盗用了函数中的极值点的概念),其周围 4 个方向的点都必须与它等高,或者比它高度小 1。
如果只有一个最高点,那么是很简单的(一次 BFS 即可完成),但这里可能会出现多个最高点。
这里我们采用堆思想,从堆顶得到最高点,观察其 4 个相邻点的高度,判断是否需要填充高度。若需要,那么更新这个相邻点的高度(同时记录增加了多少高度),并把这个相邻点也放入堆中。
代码实现用了 set
取替代堆了,反正我们只要能在 \(O(1)\) 时间内得到最高点即可。
时间复杂度 \(O(n\log{n}), n=rc\) .
#include <iostream>
#include <vector>
#include <set>
using namespace std;
#define N 301
int t, rows, cols;
int graph[N][N] = {{0}};
struct node_t
{
int x, y, height;
node_t(int xx = -1, int yy = -1, int hh = 0) : x(xx), y(yy), height(hh) {}
bool operator<(const node_t &n) const
{ return height > n.height || (height == n.height && (x < n.x || (x == n.x && y < n.y))); }
};
uint64_t solve(set<node_t> &s)
{
uint64_t ans = 0;
static const vector<pair<int, int>> dirs = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
while (!s.empty())
{
auto [x, y, height] = *s.begin();
s.erase(s.begin());
for (auto &d : dirs)
{
int dx = x + d.first, dy = y + d.second;
if (dx < 0 || dx >= rows || dy < 0 || dy >= cols) continue;
if (graph[dx][dy] <= height - 2)
{
ans += height - 1 - graph[dx][dy];
s.erase(node_t(dx, dy, graph[dx][dy]));
graph[dx][dy] = height - 1;
s.emplace(dx, dy, graph[dx][dy]);
}
}
}
return ans;
}
int main()
{
cin >> t;
for (int k = 1; k <= t; k++)
{
cin >> rows >> cols;
set<node_t> s;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
cin >> graph[i][j];
s.emplace(i, j, graph[i][j]);
}
}
printf("Case #%d: %llu\n", k, solve(s));
}
}
Checksum
一个重要结论:如果某行/某列,只有一个元素被损坏,那么是可以通过该行/该列的校验和进行还原的,这种情况下不需要任何的 cost
.
我们把每行,每列都看作一个点,如果位置 (i, j)
为 -1 ,那么就把 row[i]
和 col[j]
连接起来,这样会得到一个二分图。
对于度为 1 的点,说明该行/列,只有 1 个 -1,那么这个数据可以通过检验和还原,不需要任何的 cost
,我们在图中去掉所有这样的边,并且去掉之后,产生的新的度为 1 的点也需要同样的操作。
上述的性质表明,如果得到图是一颗树,那么所有的数据都能通过校验和还原。
比如下图的边 (row[1], col[2])
和 (row[4], col[1])
就是这样的边。
对于剩下的边所组成的图中,我们要去掉一些边,然后令整个图成为一棵树。显然,去除 (row[i], col[j])
这条边时,需要耗费 B[i, j]
。
我们的目的是,去除权值最小的边,得到图的一棵树。换而言之,就是求出图的最大生成树 tree
。那么去除边所使用的权值就是 sum(graph) - sum(tree)
.
代码实现
#include <iostream>
#include <unordered_map>
#include <vector>
#include <queue>
using namespace std;
#define N 502
#define getrowid(r) (r)
#define getcolid(c) (n + c)
int nt;
int A[N][N] = {{0}}, B[N][N] = {{0}};
int R[N] = {0}, C[N] = {0};
struct node_t
{
int x, y, cost;
node_t(int xx, int yy, int cc) : x(xx), y(yy), cost(cc) {}
bool operator<(const node_t &node) const { return cost < node.cost; }
};
int find(vector<int> &root, int x) { return root[x] == -1 ? x : root[x] = find(root, root[x]); }
uint64_t solve(int n)
{
unordered_map<int, unordered_map<int, int>> g;
vector<int> degree(2 * n + 1, 0);
int rid, cid;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (A[i][j] == -1)
{
rid = getrowid(i), cid = getcolid(j);
g[rid][cid] = g[cid][rid] = B[i][j];
degree[rid]++, degree[cid]++;
}
}
}
// 去除度为 1 的点和这条边
for (int i = 1; i <= 2 * n; i++)
{
if (degree[i] == 1)
{
int vex = g[i].begin()->first;
degree[i]--, degree[vex]--;
g.erase(i);
if (g.count(vex))
{
g[vex].erase(i);
if (g[vex].empty()) g.erase(vex);
}
}
}
// 使用 并查集 + Kruskal 求最大生成树
priority_queue<node_t> q;
vector<int> root(2 * n + 1, -1);
uint64_t sum = 0;
for (auto &[x, m] : g)
for (auto [y, c] : m)
q.emplace(x, y, c), sum += c;
// g 是邻接矩阵,里面有重复的边
sum /= 2;
// cost 计算最大生成树
uint64_t cost = 0;
while (!q.empty())
{
auto [x, y, c] = q.top();
q.pop();
x = find(root, x), y = find(root, y);
if (x != y)
{
root[y] = x;
cost += c;
}
}
return sum - cost;
}
int main()
{
cin >> nt;
int n;
for (int t = 1; t <= nt; t++)
{
cin >> n;
uint64_t sum = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> A[i][j];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> B[i][j];
for (int j = 1; j <= n; j++) cin >> R[j];
for (int j = 1; j <= n; j++) cin >> C[j];
printf("Case #%d: %llu\n", t, solve(n));
}
}
[Kick Start] 2021 Round A的更多相关文章
- [Kick Start] 2021 Round B
题目:Kick Start 2021 Round-B . Increasing Substring 输出字符串中每个字符的最长 Increasing Substring 的长度,非常简单的动态规划问题 ...
- kick start 2019 round D T3题解
---恢复内容开始--- 题目大意:共有N个房子,每个房子都有各自的坐标X[i],占据每个房子需要一定花费C[i].现在需要选择K个房子作为仓库,1个房子作为商店(与题目不同,概念一样),由于仓库到房 ...
- kick start 2019 round D T2题解
题目大意:由N个房子围成一个环,G个人分别顺时针/逆时针在房子上走,一共走M分钟,每分钟结束,每个人顺/逆时针走到相邻的房子.对于每个房子都会记录最后时刻到达的人(可能是一群人).最终输出每个人会被几 ...
- Kick Start 2019 Round A Contention
$\DeclareMathOperator*{\argmax}{arg\,max}$ 题目链接 题目大意 一排 $N$ 个座位,从左到右编号 $1$ 到 $N$ . 有 $Q$ 个预定座位的请求,第 ...
- Kick Start 2019 Round H. Elevanagram
设共有 $N = \sum_{i=1}^{9} A_i$ 个数字.先把 $N$ 个数字任意分成两组 $A$ 和 $B$,$A$ 中有 $N_A = \floor{N/2}$ 个数字,$B$ 中有 $N ...
- Kick Start 2019 Round A Parcels
题目大意 $R \times C$ 的网格,格子间的距离取曼哈顿距离.有些格子是邮局.现在可以把至多一个不是邮局的格子变成邮局,问每个格子到最近的邮局的曼哈顿距离的最大值最小是多少. 数据范围 $ 1 ...
- Kick Start 2019 Round B Energy Stones
对我很有启发的一道题. 这道题的解法中最有思维难度的 observation 是 For simplicity, we will assume that we never eat a stone wi ...
- 【DP 好题】Kick Start 2019 Round C Catch Some
题目链接 题目大意 在一条数轴上住着 $N$ 条狗和一个动物研究者 Bundle.Bundle 的坐标是 0,狗的坐标都是正整数,可能有多条狗住在同一个位置.每条狗都有一个颜色.Bundle 需要观测 ...
- Kick Start 2019 Round F Teach Me
题目链接 题目大意 有 $N$ 个人,$S$ 项技能,这些技能用 $1, 2, 3, \dots, S$ 表示 .第 $i$ 个人会 $c_i$ 项技能($ 1 \le c_i \le 5 $).对于 ...
随机推荐
- Flutter Widgets
Flutter Widgets Flutter 组件 Syncfusion Flutter Widgets 所有组件均支持即装即用的 Android,iOS和 Web not free https:/ ...
- Paint Tool SAI
Paint Tool SAI PC 绘画工具 https://en.wikipedia.org/wiki/Paint_Tool_SAI refs https://www.systemax.jp/en/ ...
- bob and brad physical therapy knee exercise
bob and brad physical therapy knee exercise 鲍勃和布拉德物理治疗膝关节运动 https://bobandbrad.com/ youtube https:// ...
- React & CSS Modules & CSS in JS
React & CSS Modules & CSS in JS https://codesandbox.io/s/css-modules-name-mangling-ck1eo CSS ...
- nasm astrlwr_s函数 x86
xxx.asm %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export ast ...
- socket通信框架——boost asio
boost asio是一个封装了基本socket的跨平台通信框架.它支持异步访问,并支持tcp的自动封闭控制等操作. 一个简单的通信协议可以为: header body body长 数据 通过boos ...
- nginx反向代理理解
实际开发中,会有不同的环境: - 开发环境:自己的电脑- 测试环境:提供给测试人员使用的环境- 预发布环境:数据是和生成环境的数据一致,运行最新的项目代码进去测试- 生产环境:项目最终发布上线的环境 ...
- 【Notes_9】现代图形学入门——光线追踪(基本原理)
跟着闫令琪老师的课程学习,总结自己学习到的知识点 课程网址GAMES101 B站课程地址GAMES101 课程资料百度网盘[提取码:0000] 目录 光线追踪 为什么要光线追踪 soft shadow ...
- HDOJ-1686(KMP算法)
Oulipo HDOJ-1686 本题的思路就是KMP,和HDOJ-1711思路一样,不再赘述详情可以看链接:1711题解 #include<iostream> #include<c ...
- python基础学习之简化占位符和格式化的概念
简化版占位符有哪些? %s 字符串占位符,代表该位置有一个字符串待替换(万能) %d 数字占位符,代表该位置有一个数字待替换 %f 同上,这里是浮点数,float[默认保留6位小数] % ...