首页 > 其他分享 >Atcoder ABC 353 全题解

Atcoder ABC 353 全题解

时间:2024-05-12 22:30:51浏览次数:27  
标签:Atcoder ABC sz int 题解 ll ans bit lld

最近看的人好少……都快不想写了……

你们的支持就是我创作的最大动力!

AB

%你

CDE

题意:有一个一个一个函数,把函数两两配对式求值,求这些值最后的总和

C

考虑将所有的和减去 $ 10^8 $ 出现的次数。

将整个数组排序,然后进行二分,求第一个与这个数的和 $ \ge 10^8 $ 的位置,然后与这个数的位置取 max,看后面的数的数量即可。

// Problem: C - Sigma Problem
// Contest: AtCoder - AtCoder Beginner Contest 353
// URL: https://atcoder.jp/contests/abc353/tasks/abc353_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define mod 100000000ll

ll a[300005];

int main() {
	int n;
	scanf("%d", &n);
	ll ans = 0;
	for (int i = 0; i < n; i++) {
		scanf("%lld", &a[i]);
		ans += a[i] * (n - 1);
	}
	sort(a, a + n);
	for (int i = 0; i < n; i++) {
		int cnt = n - max((int)(lower_bound(a, a + n, mod - a[i]) - a), i + 1);
		ans -= mod * cnt;
	}
	printf("%lld", ans);
}

D

两个数拼凑,比如 $ a $ 位的 $ x $ 和 $ b $ 位的 $ y $,组成的数为 $ 10^bx + y $。

因此,我们可以考虑每个数的 $ 10^b $,那么一个数对答案的贡献,就等于它后面的数的 $ 10^b $ 之和,加上前面的数的数量,再将和乘上自己得到的结果。

可以倒序扫描,也可以用后缀和。

// Problem: D - Another Sigma Problem
// Contest: AtCoder - AtCoder Beginner Contest 353
// URL: https://atcoder.jp/contests/abc353/tasks/abc353_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define mod 998244353

ll a[200005], suf[200005];
ll prod[200005];

ll calc_prod(ll x) {
	ll ans = 1;
	while (x) {
		ans *= 10;
		x /= 10;
	}
	return ans;
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%lld", &a[i]);
		suf[i] = a[i];
		prod[i] = calc_prod(a[i]);
		a[i] %= mod;
	}
	for (int i = n - 1; i >= 0; i--) {
		suf[i] = (suf[i] + suf[i + 1]) % mod;
		prod[i] = (prod[i] + prod[i + 1]) % mod;
	}
	ll ans = 0;
	for (int i = 0; i < n; i++) {
		ans = (ans + a[i] * prod[i + 1] % mod + suf[i + 1]) % mod;
	}
	printf("%lld", ans);
}

E

前缀?Trie 树走上!

先把所有字符串插进去,然后进行 dfs 或遍历。

对于一个节点,统计里面的字符串数量 $ n $,那么答案就会额外加 $ \frac{n(n - 1)}{2} $。

// Problem: E - Yet Another Sigma Problem
// Contest: AtCoder - AtCoder Beginner Contest 353
// URL: https://atcoder.jp/contests/abc353/tasks/abc353_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define ll long long

int trie[300005][26];
ll val[300005], cnt = 1;

void insert(string s) {
	int node = 0;
	val[0]++;
	for (char x : s) {
		if (trie[node][x - 'a'] == -1) {
			trie[node][x - 'a'] = cnt++;
		}
		node = trie[node][x - 'a'];
		val[node]++;
	}
}

int main() {
	memset(trie, -1, sizeof trie);
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		string s;
		cin >> s;
		insert(s);
	}
	ll ans = 0;
	for (int i = 1; i < cnt; i++) {
		ans += val[i] * (val[i] - 1) / 2;
	}
	printf("%lld", ans);
}

F

首先在一个标准方格纸上走,找出最坏情况。

接着,考虑三种情况:

  1. $ L \to L $

  2. $ L \to S $

  3. $ S \to S $

(第二种包括了 $ S \to L $)

首先考虑核心的第一种情况。

从一个大块走到斜对角相邻的另一个大块,可以从它们夹着的小块过去,代价为2,那么一般来说,代价就是坐标除以 $ K $ 后的切比雪夫距离乘 2。

但是也有特例:

image

这时候就应该走红色而非绿色。

那怎么办?没办法,只能特判 $ K = 2 $ 的情况!

有了 $ L \to L $ 的基础,23 两类情况就很好处理了,先枚举一个方向从 $ S $ 走到 $ L $,然后再 $ L \to L $ 处理即可。

// Problem: F - Tile Distance
// Contest: AtCoder - AtCoder Beginner Contest 353
// URL: https://atcoder.jp/contests/abc353/tasks/abc353_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define ll long long

bool large(ll bx, ll by) {
	return (bx + by) & 1;
}

// X-1,X+1,Y-1,Y+1

ll s_to_l(ll x, ll y, ll sz, int dir) {
	x %= sz, y %= sz;
	if (dir == 0) {
		return x + 1;
	} else if (dir == 1) {
		return sz - x;
	} else if (dir == 2) {
		return y + 1;
	} else {
		return sz - y;
	}
}

ll dis_l(ll bx1, ll by1, ll bx2, ll by2, ll sz) {
	if (sz == 1) {
		return abs(bx1 - bx2) + abs(by1 - by2);
	} else if (sz == 2) {
		ll ans = min(abs(bx1 - bx2), abs(by1 - by2)) * 2;
		ans += (max(abs(bx1 - bx2), abs(by1 - by2)) - min(abs(bx1 - bx2), abs(by1 - by2))) / 2 * 3;
		return ans;
	}
	return max(abs(bx1 - bx2), abs(by1 - by2)) * 2;
}

ll dx[] = {-1, 1, 0, 0};
ll dy[] = {0, 0, -1, 1};

int main() {
	ll sz;
	scanf("%lld", &sz);
	ll sx, sy, tx, ty;
	scanf("%lld %lld", &sx, &sy);
	scanf("%lld %lld", &tx, &ty);
	ll bsx = sx / sz, bsy = sy / sz, btx = tx / sz, bty = ty / sz;
	ll ans = abs(sx - tx) + abs(sy - ty);
	if (sz == 1) {
		printf("%lld", ans);
		return 0;
	}
	if (large(bsx, bsy) && large(btx, bty)) {
		printf("%lld", dis_l(bsx, bsy, btx, bty, sz));
	} else if (!large(bsx, bsy) && !large(btx, bty)) {
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				// cerr << i << " " << j << " ";
				// cerr << s_to_l(sx, sy, sz, i) << " " << s_to_l(sx, sy, sz, j);
				// cerr << " " << dis_l(bsx + dx[i], bsy + dy[i], btx + dx[j], bty + dy[j]) << endl;
				ans = min(ans, s_to_l(sx, sy, sz, i) + s_to_l(tx, ty, sz, j) + dis_l(bsx + dx[i], bsy + dy[i], btx + dx[j], bty + dy[j], sz));
			}
		}
		printf("%lld", ans);
	} else {
		if (!large(bsx, bsy)) {
			swap(bsx, btx);
			swap(bsy, bty);
			swap(sx, tx);
			swap(sy, ty);
		}
		for (int i = 0; i < 4; i++) {
			ans = min(ans, s_to_l(tx, ty, sz, i) + dis_l(bsx, bsy, btx + dx[i], bty + dy[i], sz));
		}
		printf("%lld", ans);
	}
}

G

考虑 DP,设 $ f_i $ 为我们必须参加第 $ i $ 场最多能赚到的钱。

聪明的你肯定已经想到了一个 $ O(n^2) $ 的 DP:

\[f_i = \max_{1 \le j < i} f_j + C \cdot |i - j| \]

把转移分成两部分,从前面过来和从后面过来。

然后你就会发现,从前面过来的,由于 $ i > j $,所以可以把绝对值符号去掉!

那么,我们定一个“虚拟起点”,这个点位于所有点的后面。容易发现,从前面转移来的时候,从“虚拟起点”计算代价和从真正的点计算代价,大小关系以及差的关系仍然保持一致。

后面的同理。

现在,我们只有一个转移的起点了(即“虚拟起点”),那么我们就可以用树状数组进行单点更新,前缀查询 max 进行转移了,时间复杂度 $ O(n log n) $。

// Problem: G - Merchant Takahashi
// Contest: AtCoder - AtCoder Beginner Contest 353
// URL: https://atcoder.jp/contests/abc353/tasks/abc353_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define ll long long

int n;
ll cost, pre_bit[200005], suf_bit[200005], f[200005];

void update(int i, ll x) {
	int p = i;
	int j = n - i + 1;
	while (i < 200003) {
		pre_bit[i] = max(pre_bit[i], x - cost * (n - p)); // 虚拟起点 n
		i += (i & -i);
	}
	while (j < 200003) {
		suf_bit[j] = max(suf_bit[j], x - cost * p); // 虚拟起点 0
		j += (j & -j);
	}
}

ll query(int i) {
	int p = i;
	int j = n - i + 1;
	ll ans = -0x3f3f3f3f3f3f3f3fll;
	while (i) {
		ans = max(ans, pre_bit[i] + cost * (n - p));
		i -= (i & -i);
	}
	while (j) {
		ans = max(ans, suf_bit[j] + cost * p);
		j -= (j & -j);
	}
	return ans;
}

int main() {
	scanf("%d %lld", &n, &cost);
	int m;
	scanf("%d", &m);
	memset(pre_bit, -0x3f, sizeof pre_bit);
	memset(suf_bit, -0x3f, sizeof suf_bit);
	update(1, 0);
	ll ans = 0;
	for (int i = 1; i <= m; i++) {
		int t;
		ll p;
		scanf("%d %lld", &t, &p);
		f[i] = query(t) + p;
		// cerr << f[i] << endl;
		ans = max(ans, f[i]);
		update(t, f[i]);
	}
	printf("%lld", ans);
}

标签:Atcoder,ABC,sz,int,题解,ll,ans,bit,lld
From: https://www.cnblogs.com/AProblemSolver/p/18188317

相关文章

  • abc_353_b题解
    这道题怎么说呢……开始看题目翻译也是一脸懵,然后直接就看了样例解释,然后:瞬间明白!所以:样例解释YYDS!样例解释YYDS!!样例解释YYDS!!!停停停不开玩笑了。仍旧是分步解决问题(诶不是怎么突然联想到了加法原理):输入(每道题几乎都有的东西~~~),不用多说,按照题目要求解决。循环。这一步......
  • abc_353_a题解
    题目传送门~~~CSDN传送门~~~这题纯纯一个数组遍历。如果你看不懂英文的话,那么atcoderbetter这个插件可以帮助你,所有洛谷&atcoder&codeforces的插件都在这里:https://www.luogu.com/article/p2ri0gub咳咳……跑题了跑题了!下面就是题解:输入。这一步很简单,定义变量n和数组H......
  • P10229 [COCI 2023/2024 #4] Knjige 题解
    P10229[COCI2023/2024#4]Knjige题解知识点前缀和、贪心、枚举。题意分析一个长度为\(n\)的单调不减的数列\(\{k_i\}\),从左到右遍历,用\(a\)或\(b\)的代价,换\(0\)或\(k_i\)的价值。问:在总代价超过\(t\)之前,能够达到的最大价值为多少?思路分析显然是一个......
  • P10224 [COCI 2023/2024 #3] Vrsar 题解
    P10224[COCI2023/2024#3]Vrsar题解知识点前缀和思想,贪心。题意分析我觉得题目挺清晰了……思路部分分没必要,OK?我不会告诉你我考场上打部分分打了30min,还只有8分。正解我们设一个方案\(S\)为\(\{x_1,x_2...x_n\}\),其中\(x_i\)表示第\(i\)个滑雪场的......
  • P10225 [COCI 2023/2024 #3] Milano C.le 题解
    P10225[COCI2023/2024#3]MilanoC.le题解知识点栈,贪心,树状数组。题意分析求最小的栈的数量使得出入栈能够合法。思路分析我们为了方便,其实可以先按照到达车站的顺序(入栈顺序)给火车重新编号。编号后,就十分简单了。分析样例:53524132514编号后,就变成了:5......
  • P10232 [COCI 2023/2024 #4] Roboti 题解
    P10232[COCI2023/2024#4]Roboti题解知识点简单环,DFS。题意分析在\(n\)行,\(m\)列的网格里,给定\(k\)个转弯点,再给定\(Q\)个询问,问每次从某个坐标到另一个坐标的最少转弯次数,或者判断不可能到达。思路分析我们发现在一个点坐标与方向确定的时候,到达的下一个点的......
  • P10231 [COCI 2023/2024 #4] Putovanje 题解
    P10231[COCI2023/2024#4]Putovanje题解知识点多源BFS,bitset。题意分析在一个图上,每个点有一个权值,求满足到每个点的距离都为其权值的点(权值为\(-1\)的点除外)。思路分析Subtask1我们可以发现,这个子任务的图一定是一个有序的链,那么转换成序列问题,直接根据坐标进......
  • CF1967D Long Way to be Non-decreasing 题解
    CF1967DLongWaytobeNon-decreasing题解知识点二分答案,基环树。题意分析给定一个包含\(n\)个元素的数组\(\{a_i\}\)和一个\(m\)个元素的数组\(\{b_i\}\)。定义每次操作为:在\(\{a_i\}\)中选择任意个数,假设某个选的数为\(a_i\),那么将其变为\(b_{a_i}\)......
  • P10227 [COCI 2023/2024 #3] Slučajna Cesta 题解
    P10227[COCI2023/2024#3]SlučajnaCesta题解知识点期望DP,树形(换根)DP,组合数学。题意分析一棵树,每个点都有点权,每一条边的方向分布都是等概率的,问从每个点出发,有路走就一直走的情况下,所途径的点的权值总和的期望值。思路分析这明显是一个树形DP,且需要变成换根DP......
  • Atcoder Beginner Contest 353
    AtcoderBeginnerContest353A问题陈述有\(N\)幢楼房排列成一排。左起的\(i\)th楼高\(H_i\)。请判断是否有比左起第一座高的建筑物。如果存在这样的建筑物,请找出从左边起最左边的建筑物的位置。思路签到题。代码#include<bits/stdc++.h>usingnamespacestd;int......