Luogu 题解 AT2163

Update 2021/04/12

更新了几个错别字。。。

思路整理

作为一道构造题,要思考那些东西对结果有用,那些没用。

看看这个例子:\(1\ 5\ 3\ 7\ 6\ 2\ 4\)

暴力的思路向上推,过程:

\[{\color{red} 6} \]

\[5\ \ {\color{red} 6\ \ 6} \]

\[3\ \ 5\ \ {\color{red} 6\ \ 6}\ \ 4 \]

\[1\ \ 5\ \ {\color{red} 3\ \ 7\ \ 6\ \ 2}\ \ 4 \]

发现过程中有多个 \(6\) 出现,然后答案也是 \(6\),思考有没有什么联系。

观察形如 \(x\ x\ y\) 的三元组,在向上一层传递的时候肯定是 \(x\) (思考为什么)。

然后进一步推出 \(x\ x\ y\) 的上一层结果应该是 \(x\ x\ z\) (思考为什么)。

得到结论:当出现形如 \(x\ x\) 的排列时,所有在此排列上方的数都为 \(x\),所以这个构造题的一种思路就是使在倒数第二排时在中间有两个连续的数出现(肯定就是求的数,不然就没了),就像上面的例子。

代码实现

在代码中我定义输入的数为 \(N\)\(K\)

首先思考几个特殊情况:

  • \(K = 1\)\(K = 2 \times N - 1\) 时(即 \(K\) 处于极端数据时),无解,因为没法使其成为中位数,这个很好理解。

  • \(N = 2\) 时,有且只有 \(K = 2\) 有解,因为当 \(N = 2\) 时,结果一定为 \(2\)(思考为什么)。

于是就有了开头这一段:

cin >> N >> K;
if (K == 1 || K == 2 * N - 1) {printf ("No\n"); return 0;}
if (N == 2 && K == 2) {printf ("Yes\n1 2 3\n"); return 0;}
if (N == 2) {printf ("No\n"); return 0;}

然后输出 Yes,开始操作。

A[N] = K; A[N - 1] = K - 1; A[N + 1] = K + 1; A[N + 2] = K - 2;
for (register int i = 1, j = 1; i <= N * 2 - 1; i++){
    if (i == N - 1) i = N + 3;
    if (j == K - 2) j = K + 2;
    A[i] = j++;
}

先把第一层变成这样(上面一层是数值,下面是位置):

\[\cdots\ \ K - 1\ \ K \ \ K + 1 \ \ K - 2 \ \ \cdots \]

\[\cdots\ \ N - 1\ \ N \ \ N + 1 \ \ N + 2 \ \ \cdots \]

这样放置就可以使倒数第二层变成这样:

\[\cdots\ \ K \ \ \ \ \ K \ \ \ \ \ \cdots \]

\[\cdots\ \ N \ \ N + 1 \ \ \cdots \]

之后就能做出正确的答案。

还有一个点就是当 \(K = 2\) 时要注意不能出现 \(K - 2\) 会变成 \(0\),你就 WA 了,所以这个地方要另外处理,代码就不放了。

Made By \(\operatorname{wheneveright}\)

posted @ 2021-04-12 17:17  XJ21  阅读(43)  评论(0)    收藏  举报