CF1667C (Round #783) 题解 构造
-
鸣谢:@SpadeA261
-
挑战最短代码 -
(由于笔者太菜了不会画图,读者珂以利用方格纸辅助理解)
本题解主要讲解一种构造方式。
本文作如下定义:
-
“\(n\) 阶棋盘”即为题意中 \(n\) 行 \(n\) 列的棋盘;
-
对角线(与主对角线平行)的编号为其上格子的行号减列号。
设答案为 \(k\),考虑在 \(n\) 阶棋盘左上角的 \(k\) 阶棋盘中不重行不重列地放置 \(k\) 个棋子,于是 \(n\) 阶棋盘中的前 \(k\) 行均能被同行棋子攻击,前 \(k\) 列均能被同列棋子攻击。
于是还剩下右下角的 \(n-k\) 阶棋盘,它们只能被同对角线的棋子攻击。
\(n-k\) 阶棋盘可被划分为 \(2(n-k)-1\) 条对角线,为使它们被覆盖,需要有 \(k\ge2(n-k)-1\),
解得 \(k=\left\lceil\dfrac{2n-1}{3}\right\rceil=\left\lfloor\dfrac{2n+1}{3}\right\rfloor\),
同时 \(n=\left\lfloor\dfrac{3k+1}{2}\right\rfloor\)。
接下来考虑放置方案。
由 \(k\ge2(n-k)-1\) 变形得 \(\left\lfloor\dfrac{k+1}{2}\right\rfloor\ge n-k\),注意到 \(n-k\) 即为 \(n-k\) 阶棋盘中编号非负的对角线数量。
考虑用 \(k\) 阶棋盘中的前 \(\left\lfloor\dfrac{k+1}{2}\right\rfloor\) 列上的棋子攻击这些对角线。
首先在 \((1,1)\) 放置一枚棋子别问为什么问就是看上去很优,则它能攻击 \(0\) 号对角线;
接着采用类似“马走日”的方法,下一枚棋子放置在上一枚棋子位置行号 \(+2\),列号 \(+1\) 的位置,于是它能攻击的对角线编号 \(+1\)。
也就是像 \((3,2),(5,3)…\) 这样,依次攻击 \(n-k\) 阶棋盘中的非负对角线,直到第 \(\left\lfloor\dfrac{k+1}{2}\right\rfloor\) 列,此时棋子刚好没有超出 \(k\) 阶棋盘,同时编号非负的对角线全部被攻击到。
剩下的任务就是用 \(k\) 阶棋盘余下的列上的棋子攻击 \(n-k\) 阶棋盘余下的对角线。
在 \(k\) 阶棋盘中,考虑再下一列上的棋子,由于奇数行已全被占据,棋子应被放在偶数行,我们将它放在第二行,也就是放在 \((2,\left\lfloor\dfrac{k+1}{2}\right\rfloor+1)\)。
它能攻击的对角线,编号为 \(2-(\left\lfloor\dfrac{k+1}{2}\right\rfloor+1)=-\left\lfloor\dfrac{k-1}{2}\right\rfloor\)。
\(n-k\) 阶棋盘中编号最小的对角线,编号为 \(1-(n-k)=1-\left\lfloor\dfrac{3k+1}{2}\right\rfloor+k=-\left\lfloor\dfrac{k-1}{2}\right\rfloor\)。
于是这枚棋子刚好攻击到编号最小的对角线。
我们依旧采用上面提到的“马走日”的方法放置棋子,于是第 \(k\) 列的棋子位置是 \((2\left\lfloor\dfrac{k}{2}\right\rfloor,k)\),显然它攻击的对角线编号不是 \(0\) 就是 \(-1\),此时编号为负的对角线也全部被攻击到。
至此我们完成了全部分析。
在代码实现中,我们可以枚举列号,按上面的方法模拟行号的变化。
代码很短,在 \(0.2kb\) 以内传说中思维很巧妙代码很好写的题。
#include<cstdio>
int n,k;
int main(){
scanf("%d",&n);
k=(n*2+1)/3;
printf("%d",k);
for(int i=1,x=-1;i<=k;++i){
if((x+=2)>k) x=2;
printf("\n%d %d",x,i);
}
return 0;
}

浙公网安备 33010602011771号