【Atcoder】 [ABC221G] Jumping sequence

题目链接

Atcoder方向
Luogu方向

题目解法

因为上下左右是对横纵坐标分别修改的,不好操作,考虑如何只考虑一维限制
考虑一个重要套路:将坐标轴旋转 45 ° 45\degree 45°,这样终点坐标会变为 A + B , A − B A+B,A-B A+B,AB
然后对横纵坐标分开做背包,然后记录方案即可
可以发现 d p dp dp 过程可以用 b i t s e t bitset bitset 优化,所以时间复杂度 O ( n 2 d ω ) O(\frac{n^2d}{\omega}) O(ωn2d)

#include 
using namespace std;
const int N(2010),D(1810);
int n,A,B,tA,tB,d[N];
bitset<N*D> bs[N];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
int main(){
	n=read(),tA=read(),tB=read();A=tA+tB,B=tA-tB;
	int tot=0;
	for(int i=1;i<=n;i++) d[i]=read(),tot+=d[i];
	reverse(d+1,d+n+1);
	if(((A+tot)&1)||((B+tot)&1)){ puts("No");exit(0);}
	if(A+tot<0||B+tot<0||A>tot||B>tot){ puts("No");exit(0);}
	bs[0][0]=1;
	for(int i=1;i<=n;i++) bs[i]=bs[i-1]|(bs[i-1]<<d[i]);
	if(!bs[n][(A+tot)/2]||!bs[n][(B+tot)/2]){ puts("No");exit(0);}
	puts("Yes");
	int cur1=(A+tot)/2,cur2=(B+tot)/2;
	for(int i=n;i>=1;i--){
		bool f1=0,f2=0;
		if(cur1>=d[i]&&bs[i-1][cur1-d[i]]) cur1-=d[i],f1=1;
		if(cur2>=d[i]&&bs[i-1][cur2-d[i]]) cur2-=d[i],f2=1;
//		cout<
		if(f1&&f2) putchar('R');
		if(f1&&!f2) putchar('U');
		if(!f1&&f2) putchar('D');
		if(!f1&&!f2) putchar('L'); 
	}
	return 0;
}

你可能感兴趣的:(Atcoder,算法)