351
A - The bottom of the ninth
高桥队和青木队正在进行一场棒球比赛,高桥队是第一棒。
目前,比赛已进行到第九局上半,第九局下半即将开始。
高桥队在
第九局上半结束时,高桥队的得分不低于青木队的得分。
求青木队在第九局下半至少需要得到多少分才能赢得比赛。
在这里,如果比赛在第九局下半结束时打成平手,结果就是平局。因此,青木队要想获胜,就必须在第九局下半结束时比高桥队严格多得一分。
高桥队在任何时候的得分都是截至该点的上局总得分,而青木队的得分则是下局的总得分。
void solve() {
int cnt1 = 0, cnt2 = 0;
for (int i = 1;i <= 9;i++) {
int x;cin >> x;cnt1 += x;
}
for (int i = 1;i <= 8;i++) {
int x;cin >> x;cnt2 += x;
}
cout << cnt1 - cnt2 + 1 << '\n';
}
B - Spot the Difference
给你两个网格,每个网格有
网格中的每个单元格都包含一个小写英文字母。
网格
位于网格
这两个网格正好有一个单元格不同。也就是说,存在一对不大于
char s1[110][110], s2[110][110];
void solve() {
int n;cin >> n;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
cin >> s1[i][j];
}
}
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
cin >> s2[i][j];
}
}
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
if (s1[i][j] != s2[i][j]) {
cout << i << " " << j << '\n';
}
}
}
}
C - Merge the balls
你有一个空序列和
你将进行
在
- 如果序列中只有一个或更少的球,则结束操作。
- 如果序列中最右边的球和第二个最右边的球大小***不同,结束操作。
-
- 如果序列中最右边的球和最右边的第二个球的大小**相同,则移除这两个球,并在序列的右端添加一个新球,其大小等于移除的两个球的大小之和。然后回到步骤 1,重复上述过程。
计算经过
void solve() {
int n;cin >> n;vector<int> a;
for (int i = 1;i <= n;i++) {
int x;cin >> x;
a.push_back(x);
if (a.size() <= 1) continue;
while (a.size() >= 2 && a[a.size() - 1] == a[a.size() - 2]) {
a.erase(a.begin() + a.size() - 1);
a[a.size() - 1]++;
}
}
cout << a.size() << '\n';
}
D - Grid and Magnet
有一个行数为
网格的状态由长度为
身穿铁甲的高桥可以在网格中做如下移动:
- 如果与当前单元格垂直或水平相邻的任何一个单元格中含有磁铁,他就不能移动。
- 否则,他可以移动到任何一个垂直或水平相邻的单元格。
但是,他不能离开网格。
对于每个没有磁铁的单元格,将其自由度定义为他从该单元格重复移动所能到达的单元格数。求网格中所有没有磁铁的单元格的最大自由度。
这里,在自由度的定义中,"他可以通过重复移动到达的单元格 "指的是从初始单元格通过一定的移动序列(可能是零移动)可以到达的单元格。不一定要有一个移动序列能从初始单元格开始访问所有这些可到达的单元格。具体来说,每个单元格本身(没有磁铁)总是包含在从该单元格可到达的单元格中。
这个题目在赛时
cnt
数组开小了没有报 RE,却是 WA
总体思路较为简单,将 #
周围的标记为 1,将走过的路标记为 2,这样使得每次进入一个连通块时只访问一次标记为 1/2 的,这样就能算出在每个连通块内能走的路程。
char s[1010][1010];
int vis[1010][1010], dx[] = {0,0,1,-1}, dy[] = {1,-1,0,0};
void solve() {
int n, m;cin >> n >> m;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
cin >> s[i][j];
if (s[i][j] == '#') {
if (i - 1 >= 1)vis[i - 1][j] = 1;
if (i + 1 <= n) vis[i + 1][j] = 1;
if (j + 1 <= m) vis[i][j + 1] = 1;
if (j - 1 >= 1) vis[i][j - 1] = 1;
}
}
}
int k = 0, ans = 1;
auto bfs = [&](int sx, int sy) {
map<pair<int, int>, int>once;
queue<pair<int, int>>q;q.push({sx,sy});vis[sx][sy] = 2;k++;
while (q.size()) {
auto [x, y] = q.front();q.pop();
for (int i = 0;i < 4;i++) {
int a = x + dx[i], b = y + dy[i];
if (a < 1 || b<1 || a>n || b>m || vis[a][b] == 2 || s[a][b] == '#')continue;
if (vis[a][b] == 1) {
if (!once.count({a,b})) {
once[{a, b}] = 1; k++;
}
continue;
}
q.push({a,b});vis[a][b] = 2;k++;
}
}
};
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
if (s[i][j] == '.' && !vis[i][j]) {
k = 0;
bfs(i, j);
ans = max(ans, k);
}
}
}
cout << ans << '\n';
}
E - Jump Distance Sum
在坐标平面上,有
两点
一只兔子最初位于点
。
位置为的兔子可以一次跳到 、 、 或 。
被定义为从 点跳到 点所需的最少跳跃次数。
如果经过任意次数的跳跃都无法从点到达点 ,则设为 。
计算 $$\displaystyle\sum_{i=1}^{N-1}\displaystyle\sum_{j=i+1}^N \text{dist}(P_i, P_j)$$
Solution
类似题目:
P3964 松鼠聚会
将切比雪夫距离转化为曼哈顿距离:
首先,通过绕原点旋转
接下来,我们考虑距离
接下来,我们考虑经过变换后的问题。也就是说,我们令
我们进一步考虑
旋转 45° 并放大
由
设
对于
#define int long long
void solve() {
int n;cin >> n;vector<int> a[4];
for (int i = 1;i <= n;i++) {
int x, y;cin >> x >> y;
if ((x + y) % 2 == 0) {
a[0].push_back(x + y);a[1].push_back(x - y);
} else {
a[2].push_back(x + y);a[3].push_back(x - y);
}
}
int ans = 0;
for (int i = 0;i < 4;i++) {
sort(a[i].rbegin(), a[i].rend());
for (int j = 0;j < a[i].size();j++) {
ans += a[i][j] * (a[i].size() - 1 - 2 * j);
}
}
cout << ans / 2 << '\n';
}
F - Double Sum
给你一个整数序列
请计算以下表达式:
约束条件保证答案小于
。
Solution
树状数组/线段树/扫描线
树状数组求
小的元素:牛客
在这里,对于一个固定的
利用这个事实,可以通过扫描线算法来解决这个问题,方法如下。
- 准备一个管理以下两个值的数据结构:
- 支持两种查询的多重集
,检索不小于 的元素数。 - 支持两种查询的多重集
,检索不小于 的元素之和。
- 支持两种查询的多重集
- 同样,准备一个变量
来存储答案。最初,让 。 - 对于每个
,执行以下操作。 - 用
对 进行查询,并将响应值命名为 。 - 用
对 进行查询,并将响应值命名为 。 - 将
加到 中。 - 将
插入到 和 中。
- 用
- 打印出
的结果值。
(待更
class FenwickTree {
private:
vector<long long> bit; // 1-indexed
int n;
public:
FenwickTree(int n) {
this->n = n;
bit.assign(n + 1, 0);
}
FenwickTree(vector<int> a) : FenwickTree(a.size()) {
for (size_t i = 0; i < a.size(); i++)add(i + 1, a[i]);
}
long long sum(int i) {
long long ans = 0;
while (i)ans += bit[i], i -= i & -i;
return ans;
}
long long sum(int l, int r) {
return sum(r) - sum(l - 1);
}
void add(int i, int delta) {
while (i <= n)bit[i] += delta, i += i & -i;
}
};
int main() {
int N;
cin >> N;
vector<int> A(N);
for (int& x : A) cin >> x;
vector<int> B = A;
sort(B.begin(), B.end());
B.erase(unique(B.begin(), B.end()), B.end());
int M = B.size();
FenwickTree sum0(M), sum1(M);
long long ans = 0;
for (int i = N - 1; i >= 0; --i) {
int k = lower_bound(B.begin(), B.end(), A[i]) - B.begin() + 1;
long long c = sum0.sum(k, M);
long long s = sum1.sum(k, M);
ans += s - c * A[i];
sum0.add(k, 1);
sum1.add(k, A[i]);
}
cout << ans << '\n';
}
G - Hash on Tree
给你一棵有根的树,树上有
顶点
此外,还有一个序列
有根树的哈希值计算如下:
- 按照
的顺序定义 如下。 - 如果顶点
是叶子,则 。 - 如果顶点
不是叶子,则 ,其中 是 的子集。
- 如果顶点
- 有根树的哈希值为
。
按照给出的顺序处理
每个查询都提供了
ABC 补了写作业,作业写完就“快速见识”DP,然后开始漫长的板刷CF