2018.09.30【Atcoder Regular Contest 103】D - Robot Arms(构造)(二进制拆分)

传送门


解析:

我还能说什么。
难道是 A R C ARC ARC D D D题必考二进制拆分构造?
10 10 10以内的我考场上打表拆分还打错了。

思路:

显然每一个数都是可以用二进制凑出来的,
但是这道题问题在于这里有每组两个数要凑,
而且你还必须用若干个数加或减来凑。

最不好做的就是,每一个数还不能不用。。。

至少 D D D在我看来比 E E E还难。

但是我们只需要 { 1 , 2 , 4 , 8 , , 16 , 32 , . . . 2 k } \{1,2,4,8,,16,32,...2^{k}\} {1,2,4,8,,16,32,...2k}这些边,我们就能够凑出顶点为 ( 2 k + 1 − 1 , 0 ) , ( − 2 k + 1 + 1 , 0 ) , ( 0 , 2 k + 1 − 1 ) , ( 0 , − 2 k + 1 + 1 ) (2^{k+1}-1,0),(-2^{k+1}+1,0),(0,2^{k+1}-1),(0,-2^{k+1}+1) (2k+11,0),(2k+1+1,0),(0,2k+11),(0,2k+1+1)的斜正方形中所有的奇数点(横纵坐标和为奇数)。

我们证明一下:

1.当集合为{1}时,我们能够凑出 ( 1 , 0 ) , ( − 1 , 0 ) , ( 0 , 1 ) , ( 0 , − 1 ) (1,0),(-1,0),(0,1),(0,-1) (1,0),(1,0),(0,1),(0,1),符合命题。
2.当上述命题对 k k k成立时,该命题对 k + 1 k+1 k+1成立:
令第 k + 1 k+1 k+1条边分别朝向向上,下,左,右对第 k k k个斜正方形中的所有奇数点扩展一遍即可得证。(才不是因为我不想写证明)

似乎官方题解也没有证明,只有一句 B y   i n d u c t i o n By\text{ }induction By induction。。。


那么我还是证明一下吧:

证明:

上述命题对 k k k成立时,我们集合当中拥有的数就是 { 1 , 2 , 4 , 8... 2 k } \{1,2,4,8...2^k\} {1,2,4,8...2k},能够使机械臂到达任意在以 ( 2 k + 1 − 1 , 0 ) , ( − 2 k + 1 + 1 , 0 ) , ( 0 , 2 k + 1 − 1 ) , ( 0 , − 2 k + 1 + 1 ) (2^{k+1}-1,0),(-2^{k+1}+1,0),(0,2^{k+1}-1),(0,-2^{k+1}+1) (2k+11,0),(2k+1+1,0),(0,2k+11),(0,2k+1+1)为顶点的斜正方形中的奇数点。我们借助一张图片来了解一下
2018.09.30【Atcoder Regular Contest 103】D - Robot Arms(构造)(二进制拆分)_第1张图片
首先证明所有原来能够达到的位置现在仍然能够到达。

其中蓝绿橙黄四个小正方形是我们原来能够到达的点抽象成的区域
我们用前 k k k条边达到蓝色区域,再将第 k + 1 k+1 k+1条边上指,便可以得到绿色区域。
同理,我们用前 k k k条边达到绿色区域,再将第 k + 1 k+1 k+1条边下指,便可以得到蓝色区域。橙色和黄色作相同考虑。

所以原来能够达到的现在仍然能够达到。

再证明所有大正方形里面的点都能够达到。
首先,我们取原来正方形的上半部分,将第 k + 1 k+1 k+1条边上指,得到上面的黄色大三角形,其他角的大三角形同样。

那么,还剩下形如图中包含紫色小三角形的大三角形没有凑出。
我们将绿色正方形剖开,取右半部分,将第 k + 1 k+1 k+1条边左指,得到紫色小三角形,其他的以此类推。


而偶数点可以通过坐标减1变为奇数点,我们只需要加上一条长度为1的机械臂就行了。

那么问题就是怎么实现了。
实现这里官方题解真的是讲得模糊。

问一个弱智问题,我们是怎么比较两个数大小的?
先看位数,位数确定再从高位比较。

这是一种贪心策略。
并且可以适用于这道题。

我们从最长的那条机械臂开始讨论方向,确定它的位置,使得它的终点与我们的目标的曼哈顿距离最小,然后以这个终点为下一条机械臂的起点,继续我们的贪心策略,上面已经证明了有解,那么这样的策略一定能够得到一组合法的解。

由于我懒得写 题目中没有要求最优解(即最小化边的数量),我每次都直接上30条机械臂。


代码:

#include
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))f^=c=='-';num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return f?-num:num;
}

inline
void outint(ll a){
	static char ch[23];
	if(a==0)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

cs ll INF=0x3f3f3f3f3f3f3f3f;
cs int N=1005;
cs int dx[4]={1,-1,0,0};
cs int dy[4]={0,0,-1,1};
cs char s[4]={'R','L','D','U'};

int n;
ll x[N],y[N];
vector<ll> len;
bool flag;

signed main(){
	n=getint();
	for(int re i=1;i<=n;++i){
		x[i]=getint(),y[i]=getint();
		if(i^1){
			if(((x[i]^y[i])&1)!=flag)return puts("-1"),0;
		}
		else flag=(x[i]^y[i])&1;
	}
	for(int re i=0;i<=30;++i){
		len.push_back(1ll<<i);
	}
	if(flag==0)len.push_back(1);
	
	sort(len.rbegin(),len.rend());
	
	outint(len.size()),pc('\n');
	for(int re i=0;i<len.size();++i)
	outint(len[i]),pc(' ');
	pc('\n');
	
	for(int re i=1;i<=n;++i){
		ll xx=x[i],yy=y[i];
		for(int re j=0;j<len.size();++j){
			int pos;
			ll minn=INF;
			for(int re k=0;k<4;++k){
				ll tmpx=xx-len[j]*dx[k];
				ll tmpy=yy-len[j]*dy[k];
				if(abs(tmpx)+abs(tmpy)<minn){
					minn=abs(tmpx)+abs(tmpy);
					pos=k;
				}
			}
			pc(s[pos]);
			xx=xx-len[j]*dx[pos];
			yy=yy-len[j]*dy[pos];
		}pc('\n');
	}
	return 0;
}

你可能感兴趣的:(构造,二进制拆分)