abc 274 d 题解
abc 274 d
题意
给定一个长度为 \(N\) 的序列 \(A\) 和整数 \(x, y\)。
请你判断能否放 \(N + 1\) 个点 \(p_0, p_1, \dots, p_{N + 1}\),满足以下条件:
-
\(p_0 = (0, 0)\)。
-
\(p_1 = (A_1, 0)\)。
-
\(p_{N + 1} = (x, y)\)。
-
点 \(p_i\) 和点 \(p_{i + 1}\) 的距离为 \(A_i\)。
-
线段 \(p_ip_{i + 1}\) 和线段 \(p_{i + 1}p_{i + 2}\) 所形成的夹角为 \(90\) 度。
思路
可以发现,其实题目就是问你有没有一种方法使得 \(p_{N + 1} = (x, y)\),而我们又可以发现,其实 \(x\) 就是由所有 \(A_i \ (i \ 是奇数)\) 凑成的,\(y\) 则是由所有 \(A_i \ (i \ 是偶数)\) 凑成的。
所以我们可以把 \(x, y\) 分开处理,那么就有 \(dp_{0/1, i, j}\) 表示用前 \(i\) 个数中的奇数或偶数是否可以凑出 \(j\)。
可以发现,每次都是由 \(i - 1\) 转移到 \(i\) 的,所以可以用滚动数组。
注意:由于坐标有可能是负数,所以需要将坐标偏移。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10, M = 2e4 + 10, INF = 1e4;
int n, x, y, a[N], c1 = 1, c2 = 1;
bool dp[2][2][M];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> x >> y, x += INF, y += INF;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
dp[0][0][INF + a[1]] = 1;
for (int i = 3; i <= n; i += 2, c1++) {
for (int j = 0; j < M; j++) {
if (j >= a[i]) {
dp[0][c1 % 2][j] |= dp[0][!(c1 % 2)][j - a[i]];
}
if (j + a[i] < M) {
dp[0][c1 % 2][j] |= dp[0][!(c1 % 2)][j + a[i]];
}
}
fill(dp[0][!(c1 % 2)], dp[0][!(c1 % 2)] + M, 0);
}
dp[1][0][INF] = 1;
for (int i = 2; i <= n; i += 2, c2++) {
for (int j = 0; j < M; j++) {
if (j >= a[i]) {
dp[1][c2 % 2][j] |= dp[1][!(c2 % 2)][j - a[i]];
}
if (j + a[i] < M) {
dp[1][c2 % 2][j] |= dp[1][!(c2 % 2)][j + a[i]];
}
}
fill(dp[1][!(c2 % 2)], dp[1][!(c2 % 2)] + M, 0);
}
cout << (dp[0][(c1 - 1) % 2][x] && dp[1][(c2 - 1) % 2][y] ? "Yes" : "No");
return 0;
}