ARC103_B 题解

本篇题解有其它题解都没有的正确性证明部分,希望大家能给个赞,谢谢!

题意简述

初始位置设置在 $(0,0)$,另给出 $n(1≤n≤1000)$ 组形如 $(x,y)(1\le |x|,|y|\le 10^9)$ 的目标坐标。要求构造长度为 $m$($m$ 自定,但要求 $m≤40$)的“步长”序列 $c_1,c_2,\cdots,c_m$($c_i$ 同样自定,要求 $c_i≤10^{12}$)。然后再对每一个目标坐标构造一个长度为 $m$ 的字符串(由 LRUD 四种字符构成,分别表示左、右、上、下),使得从 $(0,0)$ 开始走,第 $i$ 步按字符串第 $i$ 个字符所示的方向走长度 $c_i$,在走 $m$ 步后恰好能够走到该组目标坐标。

题目分析

ARC 的 B 题竟然是个紫的,好家伙

十分神奇的构造题。先判断无解的情况:设某一步走之前的坐标是 $(x,y)$,走后的坐标是 $(x',y')$,那么就有 $x'+y'=x+y±c_i$,也就是说这一步走完后的四种情况的 $x+y$ 的奇偶性相同。又因为每一组坐标走的步数相同,因此若题目中给出的目标坐标两两之间 $x+y$ 的奇偶性不完全相同就说明无解。

那么如果坐标的 $x+y$ 奇偶性完全相同就一定有解吗?答案是肯定的。想必大家看到题目后都能够想到 $c_i$ 的构造与“进制拆分”有关(多少有点小学奥数题的感觉)。本题就可以采用二进制和三进制表示两种方式,但使用三进制不如二进制方便,而且得到的答案也稍劣,所以本人采用的是二进制拆分。

由于一个数 $x$ 的二进制表示是一定存在且唯一的,那么我们就有了这样的一个思路雏形:可以对 $x$ 的每一个为 $1$ 的二进制位分配一个对应的 $2$ 的幂。

但这样有两个问题:由于每一步必须走,但是 $x$ 和 $y$ 的二进制表示中对应的一位都是 $0$ 怎么办?如果 $x$ 和 $y$ 的二进制表示中某一位都是 $1$ 又怎么办?

所以我们换一种思路,反过来从 $(x,y)$ 向 $(0,0)$ 走。$c_i$ 直接取 $2^k,2^{k-1},\cdots,4,2,1(2^k\ge\max(x_i,y_i))$。特别地,如果 $x+y$ 都是偶数就再添上一个 $1$ 以保证最后能到达$(0,0)$。从最大的 $2^k$ 向小的扫,每次选择 $x,y$ 当中距离当前扫到的 $2$ 的幂更近的那个(即绝对值更大的),强行让它向 $0$ 的方向走这一步并更新它自己的值(如果原来是 $0$,那么向随便一个方向走就行,本文以正向为例),不断进行下去直到 $x$ 和 $y$ 减到 $0$ 即可。这样构造出来 $m=\lceil \log_2\max(x_i,y_i)\rceil+2\le32$,满足题意。

这种方法的正确性其他题解貌似一笔带过了,在这里我稍微说一下我的思路:对最后的 $c_m=1$($x+y$ 为奇数)或者 $c_{m-1}=1$($x+y$ 为偶数)操作完之后的 $(x_0,y_0)$ 进行分析。在这里我们不妨设 $x_0,y_0\ge0,|x_0|\ge|y_0|$(其他情况类似)。只要我们证明 $(x_0,y_0)=(0,0)$($x_0+y_0$ 为奇数,直接得到答案)或者 $(1,0)$($x_0+y_0$ 为偶数,再用一个 $1$ 就可以得到答案)即可。

使用反证法,分类讨论:

  1. 若 $y_0=0$,但 $x_0>1$,那么反推操作之前的 $x_1,y_1$。若这一步是对 $y_1$ 进行操作,那么有 $y_1=\pm1$,则 $|y_1|=1<|x_1|$,与选择绝对值大的进行操作矛盾!因此这一步只能是对 $x_1$ 进行操作,即 $x_1=x_0\pm1$。若 $x_1=x_0-1$,由 $x_0>1$ 知 $x_1=x_0-1>0$,$x_1>0$ 应该 $-1$ 才对,矛盾!因此我们得到 $x_1=x_0+1>2$。那么再往前一步的 $x_2,y_2$ 仍然有 $y_2=0,x_2=x_1+2>4$(证明过程类似)以及 $y_3=0,x_3=x_2+4>8$……因此得到 $y_i=0,x_i>2^i$。考虑第一步操作,应有 $c_1=2^k\ge\max(|x|,|y|)$,然而由刚刚得到的结论却有 $x>2^k$,矛盾!因此这种情况不成立。

  2. 若 $x_0\ge y_0\ge1$,那么类似上面的过程,由每次选择 $x,y$ 中绝对值更大的进行操作以及操作方向向 $0$ 两个性质,我们仍然可以得到每次操作满足 $x_{i+1}=x_i+2^i$ 或者 $y_{i+1}=y_i+2^i$。这样我们虽然不能确定 $x_i$ 和 $y_i$ 的具体大小范围,但是可以确定 $x_i+y_i\ge2^i+1$。那么仍然考虑最初的 $x,y$ 和 $2^k$,应有 $2^k\ge\max(|x|,|y|)$。但由刚刚的结论知 $x+y\ge2^{k+1}+1$,则有 $\max(|x|,|y|)\ge\frac{2^{k+1}+1}2>2^k$,矛盾!

综上,$(x_0,y_0)=(0,0)$ 或 $(1,0)$,即这种方法一定能够得到解,是正确的。具体细节看代码。

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,k,m;
long long x[1010],y[1010],c[42];
bool fg;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&x[i],&y[i]);
        k=max(k,max((int)log2(abs(x[i])-1),(int)log2(abs(y[i])-1))+1);//判断最大的 2^k 需要到多大 
        if(i==1) 
            fg=(x[i]+y[i])&1ll;//记录 x+y 的奇偶性 
        else if(((x[i]+y[i])&1ll)!=fg)//x+y 奇偶性不同,无解 
        {
            printf("-1");
            return 0;
        }
    }
    for(long long i=k;i>=0;i--)
        c[++m]=1ll<<i;//c[i] 直接取 2^k,2^(k-1)…4,2,1 
    if(!fg)//x+y 为偶数,再添加一个 1 
        c[++m]=1;
    printf("%d\n",m);
    for(int i=1;i<=m;i++)
        printf("%lld ",c[i]);
    printf("\n");
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(abs(x[i])>abs(y[i]))//取绝对值更大的那个 
                x[i]>=0?(printf("R"),x[i]-=c[j]):(printf("L"),x[i]+=c[j]);//向 0 的方向走 
            else
                y[i]>=0?(printf("U"),y[i]-=c[j]):(printf("D"),y[i]+=c[j]);
        }
        printf("\n");
    }
    return 0;
}
posted @ 2023-08-02 23:05  Hadtsti  阅读(0)  评论(0编辑  收藏  举报  来源