ABC265 复盘

ABC265 复盘

upd in 2023/12/23,添加了 F 题的复盘

At 链接

LG 链接

[ABC265A] Apple

思路解析

判断一下一次性买 3 个便宜还是 3 个分开买便宜,选更便宜的方法尽量多买剩下的单独买即可。

code

#include<bits/stdc++.h>
using namespace std;
int n, x, y;
int main() {
	cin >> x >> y >> n;
	if(3 * x <= y) {
		cout << n * x;	
	}
	else {
		cout << y * (n / 3) + (n - (n / 3) * 3) * x;	
	}
	return 0;
}

[ABC265B] Explore

思路解析

模拟,遇到一个有奖金的房间就给时限加上对应的 y ,同时对于每个房间都减去路程所消耗的 a[i1]注意是先判断再修改时限

错因

题意不清,没注意顺序

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll n, m, t;
ll a[N], z[N];
int main() {
	cin >> n >> m >> t;
	for(int i = 1; i < n; i++) {
		cin >> a[i];
	}
	for(int i = 1; i <= m; i++) {
		int x, y;
		cin >> x >> y;
		z[x] = y;
	}
	for(int i = 1; i < n; i++) {
		if(t <= a[i]) {
			cout << "No";
			return 0;
		}
		t -= a[i];
		t += z[i + 1];
	}
	cout << "Yes";
	return 0;
}

[ABC265C] Belt Conveyor

思路解析

模拟,我用的是 dfs ,遇到之前走过的就返回,并在返回后输出-1;如果出了地图就输出当前坐标,并exit(0),防止多输出一个-1

code

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int n, m;
char ch[N][N];
bool vis[N][N];
map<char, int> dx, dy;
void init() {
	dx['U'] = -1;
	dx['D'] = 1;
	dy['L'] = -1;
	dy['R'] = 1;
}
void dfs(int x, int y) {
	if(vis[x][y]) return;
	vis[x][y]= true;
	int nx = x + dx[ch[x][y]], ny = y + dy[ch[x][y]];
	if(nx > 0 && nx <= n && ny > 0 && ny <= m) {
		dfs(nx, ny);
	}
	else {
		cout << x << " " << y;
		exit(0);
	}
}
int main() {
	init();
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			cin >> ch[i][j];
		}
	}
	dfs(1, 1);
	cout << "-1";
	return 0;
}

[ABC265D] Iroha and Haiku (New ABC Edition)

思路解析

二分,枚举 x,剩下的变量二分即可。

错因

x 应从 0 开始枚举

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll n, a[N], p, q, r;
ll s[N];
int main() {
	cin >> n >> p >> q >> r;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		s[i] = s[i - 1] + a[i];
	}
	for(int i = 0; i <= n - 3; i++) {
		int pos1 = lower_bound(s + 1, s + n + 1, p + s[i - 1]) - s;
		if(s[pos1] - s[i - 1] == p) {
			int pos2 = lower_bound(s + 1, s + n + 1, q + s[pos1]) - s;
			if(s[pos2] - s[pos1] == q) {
				int pos3 = lower_bound(s + 1, s + n + 1, r + s[pos2]) - s;
				if(s[pos3] - s[pos2] == r) {
					cout << "Yes";
					return 0;
				}
			}
		}
	}
	cout << "No";
	return 0;
}

[ABC265E] Warp

思路解析

靠着张老师点醒我们,也是成功在赛时切掉。用 dp,首先我们对于二维矩阵不能开 109 的数组,于是可以发现我们经过的每一个点都是由题目里的三种操作得来的,所以我们遍历到的每一个点都可以用 i 个操作一 + j 个操作二 + k 个操作三 表示出来,于是我们定义 dp[i][j][k] 代表这个点经过了 i 个操作一 + j 个操作二 + k 个操作三 这么多的操作,然后由于每一个点都可以从三种状态中的任意一中推过来,所以状态计算自然就是 dp[i][j][k] = dp[i - 1][j][k] + dp[i][j - 1][k] + dp[i][j][k - 1]

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define PII pair<int, int>
const int M = 1e5 + 10;
const int mod = 998244353;
ll n, m, a, b, c, d, e, f;
ll x[M], y[M];
ll dp[310][310][310];
map<PII, int> mp;
int main() {
	cin >> n >> m >> a >> b >> c >> d >> e >> f;
	for(int i = 1; i <= m; i++) {
		cin >> x[i] >> y[i];
		mp[{x[i], y[i]}] = 1;
	}
	dp[0][0][0] = 1;
	ll ans = 0;
	for(int i = 0; i <= n; i++) {
		for(int j = 0; j <= n; j++) {
			for(int k = 0; k <= n; k++) {
				if(i > 0) {
					dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k]) % mod;
				}
				if(j > 0) {
					dp[i][j][k] = (dp[i][j][k] + dp[i][j - 1][k]) % mod;
				}
				if(k > 0) {
					dp[i][j][k] = (dp[i][j][k] + dp[i][j][k - 1]) % mod;
				}
				ll xx = i * a + j * c + k * e;
				ll yy = i * b + j * d + k * f;
				if(mp.find({xx, yy}) != mp.end()) {
					dp[i][j][k] = 0;
				}
				if(i + j + k == n) {
					ans = (ans + dp[i][j][k]) % mod;
				}
			}
		}
	}
	cout << ans;
	return 0;
}

[ABC265F] Manhattan Cafe

思路解析

非常非常有难度的一道题。思路是dp,f[i][j][k] 表示已经计算了 i 维,距离点 p 的距离为 j ,距离点 q 的距离为 k 时的整点 r 个数,由此可见我们的每一维都可以从上一维推出来,也即 f[i][j][k] 可以由 f[i1][jΔj][kΔk] 推出,这里的 Δ 是指对于每一个 r ,它和 pq 在当前这一维上所需要增加的值,具体内容可以参考这张图(我们帅气的张老师的板书):

由此图可见我们需要分类讨论在这一维上 rpq 之间的位置关系,其过程如下:

如果你能想到这一步,非常好,你已经获得了一个 O(nd3) 的程序,代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll N = 110, D = 1010, mod = 998244353;
ll n, d;
ll p[N], q[N];
ll f[N][2 * D][D], sum[2 * D][D], sum2[2 * D][D];
int main() {
	cin >> n >> d;
	for(int i = 1; i <= n; i++) {
		cin >> p[i];
	}
	for(int i = 1; i <= n; i++) {
		cin >> q[i];
	}
	f[0][0][0] = 1;
	for(int i = 1; i <= n; i++) {
		ll s = abs(p[i] - q[i]);
		for(int j = 0; j <= 2 * d; j++) {
			for(int k = 0; k <= d; k++) {
				f[i][j][k] = 0;
				for(int l = 0; l <= s; l++) {
					if(j - l >= 0 && k - s + l >= 0) {
						f[i][j][k] += f[i - 1][j - l][k - s + l];
						f[i][j][k] %= mod;
					}
				}
				for(int l = 1; j - l >= 0 && k - s - l >= 0; l++) {
					if(j - l >= 0 && k - s - l >= 0) {
						f[i][j][k] += f[i - 1][j - l][k - s - l];
						f[i][j][k] %= mod;
					}
				}
				for(int l = 1; j - s - l >= 0 && k - l >= 0; l++) {
					if(j - s - l >= 0 && k - l >= 0) {
						f[i][j][k] += f[i - 1][j - s - l][k - l];
						f[i][j][k] %= mod;
					}
				}
			}
		}
	}
	ll ans = 0;
	for(ll j = 0; j <= d; j++) {
		for(ll k = 0; k <= d; k++) {
			if(abs(j - k) <= d) {
				ans += f[n][j][k];
				ans %= mod;
			}
		}
	}
	cout << ans;
	return 0;
}

但很遗憾此题数据为 n100,d1000 无法通过。可是我们发现每一次的 f[i][j][k] 的累加都是成对角线形状累加的,于是便可轻易想到使用前缀和进行优化:

  • 对于第一种情况:可见这种情况的对角线是一条垂直于主对角线的对角线,可以用一个 sum[j][k] 表示 j,k 所存在的这条对角线从 f[i1][0][k+1] 一直累加到 f[i1][j][k] 的值。但是需要注意我们只选取对角线中结尾为 j,k 且长度最长为 |p[i]q[i]| ,因为只有这些情况的取值是符合这种情况分类讨论的判断条件的。以及如果对角线的两端小于 0 ,也就是不存在,我们就只统计剩余的存在的部分(我就是因为这里卡了一晚上,第二天才搞好。

  • 对于第二和第三种情况:可见它们所经过的对角线是一条平行于主对角线的对角线,可以用一个 sum2[j][k] 表示从这条对角线的开头累加到 f[i1][j][k] 的值。

具体内容见下图:

因为没有特判而导致卡了一晚上。。

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll N = 110, D = 1010, mod = 998244353;
ll n, d;
ll p[N], q[N];
ll f[N][2 * D][D], sum[2 * D][2 * D], sum2[2 * D][2 * D];
int main() {
	cin >> n >> d;
	for(ll i = 1; i <= n; i++) {
		cin >> p[i];
	}
	for(ll i = 1; i <= n; i++) {
		cin >> q[i];
	}
	f[0][0][0] = 1;
	for(int i = 1; i <= n; i++) {
		memset(sum, 0, sizeof(sum));
		memset(sum2, 0, sizeof(sum2));
		for(ll j = 0; j <= d; j++) {
			for(ll k = 0; k <= d; k++) {
				if(j - 1 >= 0) {
					sum[j][k] += sum[j - 1][k + 1];
					sum[j][k] %= mod;
				}
				sum[j][k] += f[i - 1][j][k];
				sum[j][k] %= mod;
				if(j - 1 >= 0 && k - 1 >= 0) {
					sum2[j][k] += sum2[j - 1][k - 1];
					sum2[j][k] %= mod;
				}
				sum2[j][k] += f[i - 1][j][k];
				sum2[k][k] %= mod;
			}
		}
		ll s = abs(p[i] - q[i]);
		for(ll j = 0; j <= d; j++) {
			for(ll k = 0; k <= d; k++) {
				f[i][j][k] = 0;
				if(k - s >= 0) {	//细节特判
					if(j - s >= 0) {
						f[i][j][k] += (sum[j][k - s] - sum[j - s][k] + f[i - 1][j - s][k]) % mod;
					}
					else {
						f[i][j][k] += (sum[j][k - s] - sum[0][k - s + j] + f[i - 1][0][k - s + j]) % mod;
					}
				}
				else {
					if(j - s >= 0) {
						f[i][j][k] += (sum[j - s + k][0] - sum[j - s][k] + f[i - 1][j - s][k]) % mod;
					}
					else {
						f[i][j][k] += (sum[j - s + k][0] - sum[0][k - s + j] + f[i - 1][0][k - s + j]) % mod;
					}
				}
				f[i][j][k] %= mod;
				if(j - 1 >= 0 && k - s - 1 >= 0) {
					f[i][j][k] += sum2[j - 1][k - s - 1];
					f[i][j][k] %= mod;
				}
				if(j - s - 1 >= 0 && k - 1 >= 0) {
					f[i][j][k] += sum2[j - s - 1][k - 1];
					f[i][j][k] %= mod;
				}
			}
		}
	}
	ll ans = 0;
	for(ll j = 0; j <= d; j++) {
		for(ll k = 0; k <= d; k++) {
			ans += f[n][j][k];
			ans %= mod;
		}
	}
	cout << ans;
	return 0;
}
posted @   2020luke  阅读(56)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示