ABC221G 解题报告
Empty_Dream · · 题解
题意
有一个无限大的平面直角坐标系,初始时你在
分析
有个套路?那就是把坐标系顺时针旋转
操作看起来比较容易,画一张坐标系可以发现,新坐标系上的单位长度是旧坐标系上的
这里需要注意到一点,每次操作横坐标和纵坐标的值更改时相同的,也就是说我们只需要处理一遍 dp 就能处理出来他们俩的可行性。
到了这一步我们的问题就转换成了能否通过
对于 dp,先将
判断完不可达之后就是回溯路径的时候了。我们看一下什么时候要取 U 和 R 都是有纵坐标的变化的,L 都是 D 有横坐标变化的,那我们就要构造一种记录方式,考虑三进制——每一个数都有唯一的三进制值,仿照这个,设横坐标取的时候权值加
至此完结撒花!!!
代码
#include <bits/stdc++.h>
using namespace std;
int n, a, b, x, y, sum;
int d[2005], pos[2005];
bitset<3600005> dp[2005];//数据范围是3.6e6……
int main(){
cin >> n >> a >> b;
x = a - b, y = a + b;//更新旋转后终点位置
for (int i = 1; i <= n; i++) cin >> d[i], sum += d[i];
if (abs(x) > sum || abs(y) > sum) return cout << "No", 0;//特判
if ((x + sum) & 1 || (y + sum) & 1) return cout << "No", 0;
x = (x + sum) / 2, y = (y + sum) / 2;//直接转化成我们dp要去做的东西
dp[1][0] = 1;//basecase 这里为了之后找路径方便计算(美观)把basecase第一维加了1,后面同理
for (int i = 1; i <= n; i++) dp[i + 1] = dp[i] | (dp[i] << d[i]);//转移
if (dp[n + 1][x] == 0 || dp[n + 1][y] == 0) return cout << "No", 0;//特判不可能到达
for (int i = n; i >= 1; i--){
int tmp = 0;
if (!dp[i][x]) x -= d[i], tmp++;//统计方法
if (!dp[i][y]) y -= d[i], tmp += 2;
pos[i] = tmp;
}
cout << "Yes\n";
for (int i = 1; i <= n; i++){
if (pos[i] == 0) cout << "L";//按统计方法输出
if (pos[i] == 1) cout << "D";
if (pos[i] == 2) cout << "U";
if (pos[i] == 3) cout << "R";
}
return 0;
}