AtCoder Beginner Contest 298 题解

题面:https://atcoder.jp/contests/abc298/tasks_print

A - Job Interview

直接模拟即可。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
int n, o, x;
char s[105];
signed main () {
	n = read ();
	scanf ("%s", s + 1);
	for (int i = 1;i <= n; ++ i) {
		o += (s[i] == 'o');
		x += (s[i] == 'x');
	}
	if (o > 0 && x == 0) printf ("Yes\n");
	else printf ("No\n");
	return 0;
}

B - Coloring Matrix

因为旋转 \(4\) 次后就会变成原样,所以只需要模拟十次甚至九次即可。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
int a[105][105], b[105][105], c[105][105], n;
inline void rotate () {
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			c[n - j + 1][i] = a[i][j];
		}
	}
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			a[i][j] = c[i][j];
		}
	}
}
inline bool check () {
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			if (b[i][j] == 0 && a[i][j] == 1) return false;
		}
	}
	return true;
}
signed main () {
	n = read ();
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			a[i][j] = read ();
		}
	}	
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= n; ++ j) {
			b[i][j] = read ();
		}
	}	
	for (int i = 0;i < 10; ++ i) {
		if (check ()) {
			printf ("Yes\n");
			return 0;
		} 
		rotate ();
	}
	printf ("No\n");
	return 0;
}

C - Cards Query Problem

每个盒子可以用 std :: priority_queue 维护,每张卡片因为要去重就用 std :: set 维护即可。

有点坑,如果不用 set 去重的话就会 TLE。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
priority_queue < int, vector < int >, greater < int > > box[200005];
set < int > card[200005];
inline void th2 (priority_queue < int, vector < int >, greater < int > > qwq) {
	priority_queue < int, vector < int >, greater < int > > tmp = qwq;
	while (!tmp.empty ()) {
		int x = tmp.top ();
		printf ("%d ", x);
		tmp.pop ();
	}
	printf ("\n");
} 
inline void th3 (int xd) {
	vector < int > need;
	need.clear ();
	for (auto x : card[xd]) need.push_back (x);
	sort (need.begin (), need.end ());
	for (auto x : need) printf ("%d ", x);
	printf ("\n");
} 
signed main () {
	int n = read (), q = read ();
	while (q --) {
		int op = read ();
		if (op == 1) {
			int x = read (), y = read ();
			if (card[x].find (y) == card[x].end ()) card[x].insert (y); 
			box[y].push (x);
		}
		else if (op == 2) {
			int x = read ();
			th2 (box[x]);
		}
		else {
			int x = read ();
			th3 (x);
		}
	}
	return 0;
}

D - Writing a Numeral

数学题一道。

我们将数的每一位用 vector 维护,模 \(998244353\) 的值用一个变量 \(S\) 维护,用一个指针指向 vector 的表头。

操作 1:\(10S + x \to S\),vector 后面插入 \(x\)

操作 2:设 vector 的表头为 \(x\),取出之后将指针右移一位,并前去最高位对应的值即可。

操作 3:无脑输出。

感觉就是水题一道,关键在于取模之后还要进行特殊的处理(x = (x % mod + mod) % mod;),某人(不是我)因为这个 WA 了。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
inline int ksm (int a, int b, int p) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return res;
}
const int mod = 998244353;
int cur = 1, i10, q, pw10[600010], siz, head = 0;
vector < int > ary;
signed main () {
	pw10[0] = 1;
	for (int i = 1;i <= 6e5 + 5; ++ i) pw10[i] = pw10[i - 1] * 10 % mod;
	ary.push_back (1); siz = 1;
	i10 = ksm (10, mod - 2, mod);
	q = read ();
	while (q --) {
		int op = read ();
		if (op == 1) {
			int x = read ();
			ary.push_back (x);
			cur = (cur * 10 + x) % mod;
			siz ++;
		}
		else if (op == 2) {
			int x = ary[head];
			head ++;
			siz --;
			cur -= x * pw10[siz] % mod;
			cur = (cur % mod + mod) % mod;
		}
		else {
			printf ("%lld\n", cur);
		}
	}
	return 0;
}

E - Unfair Sugoroku

比较裸的一道概率 dp。

\(f_{A,B,0/1}\) 为当前 Ta. 在 \(A\),Ao. 在 \(B\)\(0\) 表示该 Ta. 走,\(1\) 表示该 Ao. 走,Ta. 胜利的概率。

然后枚举 Ta. / Ao. 掷出的值,直接按概率 dp 转移即可。

边界条件:\(f_{N,x,0}=f_{N,x,1}=1,f_{x,N,0}=f_{x,N,1}=0(1 \leq x < N)\)

感觉这道题还是比较容易想,一遍就过了样例,一遍就 AC 了,还是比较的经典的。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
const int mod = 998244353;
inline int ksm (int a, int b, int p) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return res;
}
int f[105][105][2], g[105][105][2], n, a, b, p, q, ip, iq;
inline int dfs (int A, int B, int type) {
	if (g[A][B][type]) return f[A][B][type];
	g[A][B][type] = 1;
	if (type == 0) {
		int ans = 0;
		for (int i = 1;i <= p; ++ i) {
			int goal = min (A + i, n);
			ans = (ans + dfs (goal, B, type ^ 1) * ip % mod) % mod;
		}
		return f[A][B][type] = ans;
	}
	else {
		int ans = 0;
		for (int i = 1;i <= q; ++ i) {
			int goal = min (B + i, n);
			ans = (ans + dfs (A, goal, type ^ 1) * iq % mod) % mod;
		}
		return f[A][B][type] = ans;
	}
}
signed main () {
	n = read (), a = read (), b = read (), p = read (), q = read ();
	ip = ksm (p, mod - 2, mod), iq = ksm (q, mod - 2, mod);
	for (int i = 1;i < n; ++ i) {
		f[n][i][0] = 1, g[n][i][0] = 1;
		f[i][n][0] = 0, g[n][i][0] = 1;
		f[n][i][1] = 1, g[n][i][1] = 1;
		f[i][n][1] = 0, g[n][i][1] = 1;
	}
	printf ("%lld\n", dfs (a, b, 0));
	return 0;
}

F - Rook Score

枚举所有有点的列(\((R,C)\) 就选自这一列),用一个线段树维护所有有点的行的权值之和,只需要在计算每行的答案的时候减掉这一行对应的点的权值即可。

这道题感觉不难想,就是代码难写了一点(可能是我的思路问题),赛时因为数组开小了 2 倍 WA 了一发。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
int n, rc[400005], r[200005], c[200005], w[200005];
int mx[1600005], inc[1600005];
inline void push_up (int u) {mx[u] = max (mx[u << 1], mx[u << 1 | 1]);}
inline void push_down (int u) {
	if (inc[u] == 0) return ;
	inc[u << 1] += inc[u], inc[u << 1 | 1] += inc[u];
	mx[u << 1] += inc[u], mx[u << 1 | 1] += inc[u];
	inc[u] = 0;
}
inline void build (int u, int l, int r) {
	inc[u] = 0;
	if (l == r) return ;
	int mid = l + r >> 1;
	build (u << 1, l, mid), build (u << 1 | 1, mid + 1, r);
	push_up (u);
}
inline void modify (int u, int l, int r, int x, int y, int v) {
	if (x <= l && r <= y) {
		mx[u] += v;
		inc[u] += v;
		return ;
	}
	push_down (u);
	int mid = l + r >> 1;
	if (x <= mid) modify (u << 1, l, mid, x, y, v);
	if (y > mid) modify (u << 1 | 1, mid + 1, r, x, y, v);
	push_up (u);
}
inline int query (int u, int l, int r, int x, int y) {
	if (x <= l && r <= y) return mx[u];
	push_down (u);
	int mid = l + r >> 1, ans = 0;
	if (x <= mid) ans = max (ans, query (u << 1, l, mid, x, y));
	if (y > mid) ans = max (ans, query (u << 1 | 1, mid + 1, r, x, y));
	return ans;
}
map < int, int > mp;
int qwq[400005];
vector < int > R[400005], C[400005]; 
signed main () {
	n = read ();
	for (int i = 1;i <= n; ++ i) {
		r[i] = read (), c[i] = read (), w[i] = read ();
		rc[i] = r[i], rc[i + n] = c[i];
	}
	sort (rc + 1, rc + 1 + 2 * n);
	for (int i = 1;i <= 2 * n; ++ i) {
		if (rc[i] != rc[i - 1]) mp[rc[i]] = mp[rc[i - 1]] + 1;
	}
	int m = mp[rc[2 * n]];
	build (1, 1, m);
	for (int i = 1;i <= n; ++ i) {
		r[i] = mp[r[i]];
		c[i] = mp[c[i]];
		R[r[i]].push_back (i);
		C[c[i]].push_back (i);
	}
	for (int i = 1;i <= n; ++ i) {
		qwq[r[i]] += w[i];
	}
	for (int i = 1;i <= m; ++ i) modify (1, 1, m, i, i, qwq[i]);
	int ans = -9e18;
	for (int i = 1;i <= m; ++ i) {
		int tot = 0;
		for (int x : C[i]) modify (1, 1, m, r[x], r[x], -w[x]), tot += w[x];
		ans = max (ans, tot + query (1, 1, m, 1, m));
		for (int x : C[i]) modify (1, 1, m, r[x], r[x], w[x]);
	}
	printf ("%lld\n", ans);
	return 0;
}

G - Strawberry War

个人感觉这道题思维难度不算太大,但代码非常难写()。

首先要枚举一个值(一定要是某个子矩形的和)\(x\),表示分割成的每个子矩形的和的下限

那么对于这个值(\(x\)),答案就是分割成的子矩形的和的最大值减去 \(x\)(如果 \(x\) 没有出现,那么 \(x\) 还可以更大)。

那么我们可以考虑进行 dp,设 \(f_{x,Lx,Rx,Ly,Ry}\) 表示对子矩形 \(((Lx,Rx),(Ly,Ry))\) 切了 \(x\) 刀后的最大值(当然也可以存减去 \(x\) 的值的最大值),那么就枚举一下切的位置,枚举一下切出来的两个子矩形内部各切了多少刀,两者取个 max 转移即可。

赛时就是想二分最小值,就做不出来了()。

可以发现最小值一定是某个子矩形的和,每次做一个 dp 就做出来了。

思想还是挺妙的,但是也不是特别难想,正确性显然()。

吐槽一下代码有点难写()。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
int a[7][7], sum[7][7][7][7], n, m, T, f[40][7][7][7][7];
inline int dp (int th) {
	for (int Li = 1;Li <= n; ++ Li) {
		for (int Ri = Li;Ri <= n; ++ Ri) {
			for (int Lj = 1;Lj <= m; ++ Lj) {
				for (int Rj = Lj;Rj <= m; ++ Rj) {
					for (int k = 0;k <= T; ++ k) f[k][Li][Ri][Lj][Rj] = 4e18;
					if (sum[Li][Ri][Lj][Rj] >= th) f[0][Li][Ri][Lj][Rj] = sum[Li][Ri][Lj][Rj] - th;
				}
			}
		}
	}
	for (int tm = 1;tm <= T; ++ tm) {
		for (int Li = 1;Li <= n; ++ Li) {
			for (int Ri = Li;Ri <= n; ++ Ri) {
				for (int Lj = 1;Lj <= m; ++ Lj) {
					for (int Rj = Lj;Rj <= m; ++ Rj) {
						for (int lf = tm - 1;lf >= 0; -- lf) {
							for (int cut = Li + 1;cut <= Ri; ++ cut) {
								int tmp = max (f[lf][Li][cut - 1][Lj][Rj], f[tm - lf - 1][cut][Ri][Lj][Rj]); 
								f[tm][Li][Ri][Lj][Rj] = min (f[tm][Li][Ri][Lj][Rj], tmp);
							}
							for (int cut = Lj + 1;cut <= Rj; ++ cut) {
								int tmp = max (f[lf][Li][Ri][Lj][cut - 1], f[tm - lf - 1][Li][Ri][cut][Rj]);
								f[tm][Li][Ri][Lj][Rj] = min (f[tm][Li][Ri][Lj][Rj], tmp);
							}
						}
					}
				}
			}
		}
	}
	return f[T][1][n][1][m];
}
signed main () {
	n = read (), m = read (), T = read ();
	for (int i = 1;i <= n; ++ i) {
		for (int j = 1;j <= m; ++ j) {
			a[i][j] = read ();
		}
	}
	for (int Li = 1;Li <= n; ++ Li) {
		for (int Ri = Li;Ri <= n; ++ Ri) {
			for (int Lj = 1;Lj <= m; ++ Lj) {
				for (int Rj = Lj;Rj <= m; ++ Rj) {
					for (int i = Li;i <= Ri; ++ i) {
						for (int j = Lj;j <= Rj; ++ j) {
							sum[Li][Ri][Lj][Rj] += a[i][j];
						}
					}
				}
			}
		}
	}
	int ans = 9e18;
	for (int Li = 1;Li <= n; ++ Li) {
		for (int Ri = Li;Ri <= n; ++ Ri) {
			for (int Lj = 1;Lj <= m; ++ Lj) {
				for (int Rj = Lj;Rj <= m; ++ Rj) {
					int base = sum[Li][Ri][Lj][Rj];
					ans = min (ans, dp (base));
				}
			}
		}
	}
	printf ("%lld\n", ans);
	return 0;
}
posted @ 2023-05-11 17:54  CountingGroup  阅读(38)  评论(0编辑  收藏  举报