AtCoder Beginner Contest 298 题解

Posted RB16B

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;

Atcoder Beginner Contest 251 D——题解

纯文本提交,居然还能AC?
纯文本提交,居然还能AC?

以上是关于AtCoder Beginner Contest 298 题解的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242