• 题解[ABC221G Jumping sequence]


    题目

    ABC221G

    大意是你初始在((0,0)),给你一个目标点((X,Y))和一个序列(D_i),第(i)次你可以选择上下左右四个方向中的一个前进(D_i)个单位,问是否可以到达((X,Y))

    Sol

    直接做显然不好做。

    考虑转化:把坐标系顺时针旋转(45)度,目标点坐标变为((dfrac{X+Y}{2},dfrac{Y-X}{2}))

    发现现在横纵坐标可以分别考虑,也就是说问题变为给你一个序列(D_i),求序列(x_iin{1,-1}),使得:

    [sumlimits D_ix_i=w(w=dfrac{X+Y}{2}/ dfrac{Y-X}{2}) ]

    可以分开讨论。

    再进行一个转化:设(sum D_i=S),求出序列(x_i)等价于在(D_i)中选取若干个数,使得(sum x_i=dfrac{S-w}{2})

    这是一个经典的背包问题。

    (bitset)优化即可。

    总结:解题需要精巧的思路,试错的胆量。

    Code

    #include<bits/stdc++.h>
    #define N (2001)
    using namespace std;
    int n,A,B,S,d[N],x[N],y[N];
    bitset<3600010>f[N];
    inline int read(){
    	int w=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		w=(w<<3)+(w<<1)+(ch^48);
    		ch=getchar();
    	}
    	return w;
    }
    int main(){
    	n=read();
    	cin>>A>>B;
    	f[0][0]=1;
    	for(int i=1;i<=n;i++) S+=d[i]=read(),f[i]=((f[i-1]<<d[i])|f[i-1]);
    	int S1=S-(A-B),S2=S-(A+B);
    	if(S1<0||S2<0||(S1&1)||(S2)&1){puts("No");return 0;}
    	if(S1>7200000||S2>7200000){puts("No");return 0;}
    	if(!f[n][S1/2]||!f[n][S2/2]){puts("No");return 0;}
    	S1>>=1,S2>>=1;
    	for(int i=n;i>=1;i--){
    		if(S1>=d[i]&&f[i-1][S1-d[i]]) S1-=d[i],x[i]=0;
    		else x[i]=1;
    		if(S2>=d[i]&&f[i-1][S2-d[i]]) S2-=d[i],y[i]=0;
    		else y[i]=1;
    	}
    	puts("Yes");
    	for(int i=1;i<=n;i++){
            //最后记得转回来
    		if(x[i]&&y[i]) putchar('R');
    		if(x[i]&&!y[i]) putchar('D');
    		if(!x[i]&&y[i]) putchar('U');
    		if(!x[i]&&!y[i]) putchar('L');
    	}
    	puts("");
    	return 0;
    }
    

    完结撒花❀

  • 相关阅读:
    Linux之硬件资源管理
    Linux之vi 文本编辑命令
    [2]窗口程序的创建
    [1]cs辅助项目分解
    1.3 Windows操作系统
    (PYG)学习去除软件自效验
    CSUST 4006-你真的会树套树套树吗?(贪心|dp)
    CSUST 4003-你真的会泡面吗?(优先队列模拟)
    2020牛客暑期多校第八场I-Interesting Computer Game(离散化+并查集)
    2020牛客暑期多校K-Kabaleo Lite(贪心)
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/15497307.html
Copyright © 2020-2023  润新知