[思維構造] 題解 Robot Arms
阿新 • • 發佈:2020-11-04
[思維構造] 題解 Robot Arms
題目分析
好吧,這道題目按理來說應該是套路題,但是我就是不會,所以寫篇題解學習一下。
首先如果 \(X_i+Y_i\) 的奇偶性不同就無解,因為每次操作後 \(X_i+Y_i\) 的奇偶性都是固定的,不肯能出現奇偶性不同的情況。
如果 \(X_i+Y_i\) 的奇偶性全部相同,那麼必定有解,當 \(X_i+Y_i\) 為偶數的時候可以通過一次走動變成奇數,所以只考慮 \(X_i+Y_i\) 為奇數的情況。
可以使用二進位制來構造,通過序列 \(1,2,4,8,16,\dots,2^k\) 可以從 \((0,0)\) 走到任意一個滿足 \(\mbox{abs}(x)+\mbox{abs}(y)<2^{k+1}\)
\(k=0\) 時,顯然序列 \(1\) 可以到達 \((1,0),(0,1),(-1,0),(0,-1)\) 。
假設 \(1,2,4,\dots,2^{k-1}\) 滿足該條件,然後我們新加入了一個數 \(2^k\) ,如果 \((x,y)\) 滿足 \(\mbox{abs}(x)+\mbox{abs}(y)<2^{k+1}\) 並且 \(x+y\) 為奇數,那麼 \(\mbox{abs}(x)\) 和 \(\mbox{abs}(y)\) 中最多隻有一個數的二進位制第 \(k\) 位為 \(1\) ,不妨假設 \(\mbox{abs}(x)>\mbox{abs}(y)\)
當然也可以通過圖來理解,每次序列增加一個數相當於是覆蓋的點向上向下向左向右並起來的所有點:
不難發現,從 \((0,0)\) 通過序列 \(1,2,4,8,\dots,2^k\) 只有唯一的方法走到 \((x,y)\) ,直接遞迴求解即可。
參考程式碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
static char c;static int f;
for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>void write(T x){
static char q[65];int cnt=0;
if(x<0)pc('-'),x=-x;
q[++cnt]=x%10,x/=10;
while(x)
q[++cnt]=x%10,x/=10;
while(cnt)pc(q[cnt--]+'0');
}
const int maxn=1005,Base=38;
long long _[Base];
long long ABS(long long x){
return x<0?-x:x;
}
int judge(long long x,long long y,int sp){
return ABS(x)+ABS(y)<_[sp+1];
}
void solve(long long x,long long y,int sp){
if(~sp){
if(judge(x-_[sp],y,sp-1)){solve(x-_[sp],y,sp-1);pc('R');}
if(judge(x+_[sp],y,sp-1)){solve(x+_[sp],y,sp-1);pc('L');}
if(judge(x,y-_[sp],sp-1)){solve(x,y-_[sp],sp-1);pc('U');}
if(judge(x,y+_[sp],sp-1)){solve(x,y+_[sp],sp-1);pc('D');}
}
}
long long X[maxn],Y[maxn];
int main(){
int n,s=0,ok=true;read(n);
for(int i=1;i<=n;++i){
read(X[i]),read(Y[i]);
if(i==1)s=(X[i]+Y[i])&1;
else ok&=(s==((X[i]+Y[i])&1));
}
if(!ok)puts("-1");
else{
_[0]=1;
for(int i=1;i<Base;++i)
_[i]=_[i-1]<<1;
if(s&1)write(Base),pc('\n');
else write(Base+1),pc('\n'),write(1),pc(' ');
for(int i=0;i<Base;++i)write(_[i]),pc(" \n"[i==Base-1]);
for(int i=1;i<=n;++i){
if(!((X[i]+Y[i])&1))pc('L'),++X[i];
solve(X[i],Y[i],Base-1);pc('\n');
}
}
return 0;
}