0
点赞
收藏
分享

微信扫一扫

ABC-211补题报告

西曲风 2022-02-24 阅读 59
c++算法

思路参考:AtCoder Beginner Contest 221【A - G】 - Kanoon - 博客园 

G - Jumping sequence

#include <bits/stdc++.h>
using namespace std;
const int N = 2005, M = 3.6e6+5;
int n, a, b, d[N], sum;
bitset<M> bit[N];
bool addx[N], addy[N]; //记录每一步是否有add

/* 思路:考虑把二维拉伸成一维,假设只有一个方向轴,每次可以走+di或者-di,
如果既能走到a+b,又能走到a-b,那么说明可以(因为这样就说明能分成两部分,一部分是a,一部分是b),否则不行。
考虑到走+di或者-di可能会到达负坐标,不好处理,所以右移处理,每次额外走+di距离,变成走+2*di或者0,目的地变成a+b+sum和a-b+sum
然后再把走的距离/2,每次走+di或者0,目的地坐标也相应/2(注意这里已经可以排除部分情况,如果/2不是整数,说明肯定到不了)
然后进行bit压缩的dp递推,算出所有可到的地方,包含两个目的地就说明Yes,否则No
重点是还原路径:考虑把之前的坐标变换反向映射一下,具体见下。
*/
int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin>>n>>a>>b; for(int i=1; i<=n; i++) cin>>d[i], sum+=d[i];
	for(int i:{a+b+sum, a-b+sum}) //检查两个目的地是否符合题意,不符合直接No,结束
		if(i%2 || i/2<0 || i/2>sum) {cout<<"No"; return 0;} //是奇数,或者越界都不行
	int x = (a+b+sum)/2, y=(a-b+sum)/2; //两个目的地,必须都能到达
	bit[0][0] = 1; //起点init
	for(int i=1; i<=n; i++)
		bit[i] = bit[i-1]|(bit[i-1]<<d[i]); //可以不动,也可以动
	if(!bit[n][x] || !bit[n][y]) {cout<<"No"; return 0;} //其中一个到不了,结束
	cout<<"Yes"<<'\n'; //否则就一定能到达
	for(int i=n; i>=1; i--){ //原路返回找路径
		if(!bit[i-1][x]) {addx[i]=1; x-=d[i];} //i和i+1位置不同,说明i的时候动了,现在原路返回
		if(!bit[i-1][y]) {addy[i]=1; y-=d[i];}
	}
	for(int i=1; i<=n; i++){ //遍历两个add数组,映射得到原路径
		cout<<(addx[i]? (addy[i]? 'R':'U') : (addy[i]? 'D':'L'));
	}
}
/* 这里简述一下映射关系:
				不处理          方向变形              右移,除以2
	方向		(a,b)	--->   (a+b,a-b)   --->  ((a+b+sum)/2, (a-b+sum)/2)
	右          (1,0)            (1,1)                 (1,1)
	左          (-1,0)          (-1,-1)                (0,0)
	上          (0,1)            (1,-1)                (1,0)
	下          (0,-1)           (-1,1)                (0,1)
*/
举报

相关推荐

补题补题补题

abc 236 -chukodai题解报告

grep "abc" ./abc

abc

ABC 243

智能ABC

290 周赛补题

2022.4.3澳门赛区补题

0 条评论