AtCoder Beginner Contest 351

A题:The bottom of the ninth

题目大意:

两人进行共计9把比赛,现已知道打了8.5把的两人比分情况,选手A的分数大于等于B,问选手B最少要在下半场赢多少分,才能使分数高于A。

思路:

加起来减去即可,注意分数要求大于。

// Problem: A - The bottom of the ninth
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int x = 0, cnt = 9;
	while (cnt -- ) {
		int t; cin >> t;
		x += t;
	}
	cnt = 8;
	while (cnt -- ) {
		int t; cin >> t;
		x -= t;
	}
	cout << x + 1 << endl;
	return 0;
}

B题: Spot the Difference

题目大意:

给你两个网格,其中有一个位置(i,j)两个网格上的字符不同,要求你输出这个位置。

思路:

模拟即可。

// Problem: B - Spot the Difference
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n; cin >> n;
	string s[n + 1];
	for (int i = 1; i <= n; i ++ ) {
		string t; cin >> t;
		t = " " + t;
		s[i] = t;
	}
	int x, y;
	for (int i = 1; i <= n; i ++ ) {
		string t; cin >> t;
		t = " " + t;
		for (int j = 1; j <= n; j ++ ) {
			if (s[i][j] != t[j]) {
				x = i, y = j;
			}
		}
	}
	cout << x << ' ' << y << endl;
	return 0;
}

C题: Merge the balls

题目大意:

一开始你得到一个空序列和N个球,每次按顺序放入一个球,如果前后两个球的值相同,那么就可以合成一个值+1的球,直到序列剩一个球或者前后不等为止。

思路:

栈的模拟,如果一样那么pop()弹出,值+1。

可证时间复杂度一定是O(n)的。

// Problem: C - Merge the balls
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n; cin >> n;
	stack<ll> s;
	for (int i = 1; i <= n; i ++ ) {
		ll x; cin >> x;
		if (s.size() && s.top() == x) {
			while (s.size() && s.top() == x) {
				s.pop();
				x += 1;
			}
		}
		s.push(x);
	}
	cout << s.size() << endl;
	return 0;
}

D题: Grid and Magnet

题目大意:

你可以在一个网格上移动,一开始由你自由选择起点,要求你输出你可以到达的最多格子数。但是你会被磁铁吸住(如果你的四个方向中有#),这样你就不可以移动了。

思路:

bfs进行遍历即可。

vis数组:

众所周知,vis是来避免重复遍历的,在这个题目中,只有旁边没有磁铁#的点才可以vis打true,然后丢进queue中,因为旁边有磁铁的点是无法移动的。

可能的重复遍历:

我们不将旁边有磁铁的点丢进去,那是不是我们就不用管它的vis了呢?肯定不是,如果这个点的四周有多个旁边没有磁铁的点(被丢进queue里面的),这样就会重复计算,使得答案变大。如果要避免重复,我们需要修改vis,vis也不能简单的赋成1,因为旁边有磁铁的点可能被不同的连通块遍历到,它都能给它们提供贡献。(可以试试样例)

我这里利用了一个cnt表示它在哪一个连通块中。

// Problem: D - Grid and Magnet
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int ans = 1, cnt = 5;
int h, w; 
int vis[1010][1010];
bool check(int x, int y) {
	bool ok = true;
	for (int i = 0; i < 4; i ++ ) {
		int u = x + dx[i], v = y + dy[i];
		if (vis[u][v] == 2) ok = false;
	}
	return ok;
}
void bfs(int x, int y) {
	int res = 1;
	queue<PII> q;
	q.push({x, y});
    vis[x][y] = 1;
	while (q.size()) {
		auto t = q.front(); q.pop();
		int x1 = t.first, y1 = t.second;
		for (int i = 0; i < 4; i ++ ) {
			int x2 = x1 + dx[i], y2 = y1 + dy[i];
			if (x2 < 1 || x2 > h || y2 < 1 || y2 > w) continue;
			if (vis[x2][y2] == 1 || vis[x2][y2] == 2) continue;
			if (!check(x2, y2)) {
				if (vis[x2][y2] == cnt) continue;
				vis[x2][y2] = cnt;
				res += 1;
			}
			else {
				res += 1;
				vis[x2][y2] = 1;
				q.push({x2, y2});
			}
		}
	}
	ans = max(ans, res);
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> h >> w;
	for (int i = 1; i <= h; i ++ ) {
		for (int j = 1; j <= w; j ++ ) {
			char c; cin >> c;
			if (c == '#') {
				vis[i][j] = 2;
			}
		}
	}
	for (int i = 1; i <= h; i ++ ) {
		for (int j = 1; j <= w; j ++ ) {
			if (vis[i][j] == 0 && check(i, j)) {
				bfs(i, j);
				cnt += 1;
			} 
		}
	}
	cout << ans << endl;
	return 0;
}

E题: Jump Distance Sum

题目大意:

见题目,挺好懂的。

思路:

斜着走不适应,所以我们给向量乘以一个矩阵使其变成横竖着走。

\begin{bmatrix} cos\theta \ -sin\theta \\ sin\theta \ cos\theta \end{bmatrix}其中角度为45度,顺时针。

这样我们要求计算的就是曼哈顿距离。

放进去的时候用x+y和y-x来,最后ans/2,这样保证精度

计算绝对值之和的时候按考虑每个值对答案的贡献进行计算即可,这样就可以sort加前缀和计算了。

// Problem: E - Jump Distance Sum
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
ll op(vector<int> &a) {
	int n = a.size();
	ll res = 0, sum = 0;
	sort(a.begin(), a.end());
	for (int i = 0; i < n; i ++ ) {
		res += (ll)i * a[i] - sum;
		sum += a[i];
	}
	return res;
}
int main() { 
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n; cin >> n;
	vector<int> x[2], y[2];
	for (int i = 1; i <= n; i ++ ) {
		int a, b; cin >> a >> b;
		int t = (a + b) % 2;
		x[t].push_back(a + b);
		y[t].push_back(b - a);
	}
	ll ans = 0;
	for (int i = 0; i < 2; i ++ ) {
		ans += op(x[i]), ans += op(y[i]);
	}
	cout << ans / 2 << endl;
	return 0;
}

F题: Double Sum

题目大意:

见题目,很简明。

// Problem: F - Double Sum
// Contest: AtCoder - AtCoder Beginner Contest 351
// URL: https://atcoder.jp/contests/abc351/tasks/abc351_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 4e5 + 9;
ll tr1[N], tr2[N];
PII a[N];
int n;
int lowbit(int x) {return x & (-x);}
ll query(int u, ll tr[]) {
	ll res = 0;
	for (int i = u; i; i -= lowbit(i)) res += tr[i];
	return res;
}
void add(int u, int v, ll tr[]) {
	for (int i = u; i <= n; i += lowbit(i)) tr[i] += v;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i ++ ) {
		cin >> a[i].first;
		a[i].second = i;
	}
	sort(a + 1, a + 1 + n);
	ll ans = 0;
	for (int i = 1; i <= n; i ++ ) {
		ans += query(a[i].second - 1, tr1) * a[i].first - query(a[i].second - 1, tr2);
		add(a[i].second, 1, tr1), add(a[i].second, a[i].first, tr2);
	}
	cout << ans << endl;
	return 0;
}

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值