我还能说什么。
难道是 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+1−1,0),(−2k+1+1,0),(0,2k+1−1),(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+1−1,0),(−2k+1+1,0),(0,2k+1−1),(0,−2k+1+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;
}