CF329D The Evil Temple and the Moving Rocks
这题咋弱这么多。
题意简述
有一个 \(n \times n\) 的网格和无限的石头,整个网格被墙包围。石头有以下四种类型:
^型:这种石头会向上运动;v型:这种石头会向下运动;<型:这种石头会向左运动;>型:这种石头会向右运动。
你可以在每个格子上摆放任意石头,但是每个格子上最多只能放一个。摆放完之后你需要选择一个石头并激活它。被激活的石头将开始运动,直到撞上墙或者另一块石头,然后停下来。如果它撞到了另一块石头,被撞到的石头将开始运动。如果总撞击次数达到 \(10^7\) 次,石头也停止运动。
如果一块石头停止运动前移动了至少一个格子,那么它将会发出一次声音。
现在请你构造一个方案,使所有石头在停止运动之前至少发出了 \(x\) 次声音。
解题思路
考虑这样一个结构:
>>>.>.>.v
^.<.<.<<<
我们设第一行从左到右有 \(x\) 个连续的字符 >,设模式串为 >.,对第一行跑一遍 KMP 后的匹配数是 \(y\),那么我们从 \((1, 1)\) 开始跑,除掉最后一次撞墙的次数,总的响的次数是 \(x \times y\)。
那么我们尝试围绕这个结构来进行构造,例:
n = 10, 从 (1, 1) 出发
>>>>>>.>.v
.v.<.<<<<<
^>>>>>.>.v
.v.<.<<<<<
^>>>>>.>.v
.v.<.<<<<<
^>>>>>.>.v
^v.<.<<<<<
^>>>>>.>.v
^..<.<<<<<
具体说说这个结构吧,已知输入的数字 \(n\),那么我们设 \(k = \frac{n}{2}\),对于最左边的那一列,从下到上重复 \(\frac{n}{2}\) 次 ^,在这之后,一直交替重复 ^、. 即可。然后对于每行的第 \(2\) 到第 \(n\) 个,一半是重复的 > 或 <,一半是交替重复的 . 和 < 或 >,然后对于每一行的第二个字符或结尾,改为 v 即可。
当然我还学到一种构造方法,比较相似但不完全相同(感谢 lyx %%%):
n = 10, 从 (1, 1) 出发
>>>>>.>.>v
^.<.<.<<<<
v<.<.<<<<<
>>>>.>.>.^
>>>>>.>.>v
^.<.<.<<<<
v<.<.<<<<<
>>>>.>.>.^
>>>>>.>.>v
^.<.<.<<<<
拆分开来可以看做是两种结构不断重复:
>>>>.>.v
^<.<.<<<
>>>>.>.v
^<.<.<<<
对于每种结构,第一行都会有连续的 \(x\) 个 > 或 <,然后第二行有连续的 \(x - 1\) 个 > 或 <,其余的差不多,可以直接观察看一下。
假设 \(n\) 为二的倍数,\(x = \frac{n}{2}\),那么其发出的响声次数就为:
也是能稳过的。
代码实现
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int k;
char stone[305][305];
void solve1(){
int n = k, x = k >> 1;
for(int i = n - x + 1; i <= n; ++i)
stone[i][1] = '^';
for(int i = n - x; i > 0; i -= 2)
stone[i][1] = '.', stone[i - 1][1] = '^';
stone[1][1] = '>';
++x;
for(int i = 1; i <= x; ++i){
for(int j = 1; j <= n; j += 2)
stone[j][i + 1] = '>';
for(int j = 2; j <= n; j += 2)
stone[j][n - i + 1] = '<';
}
for(int i = x + 1; i < n; ++i){
char c1 = (i - x) & 1 ? '.' : '>';
char c2 = (i - x) & 1 ? '.' : '<';
for(int j = 1; j <= n; j += 2)
stone[j][i + 1] = c1;
for(int j = 2; j <= n; j += 2)
stone[j][n - i + 1] = c2;
}
for(int j = 1; j <= n; j += 2){
stone[j][n - 1] = stone[j + 1][3] = '.';
stone[j][n] = stone[j + 1][2] = 'v';
}
stone[n][2] = '<';
for(int i = 1; i <= k; ++i)
printf("%s\n", stone[i] + 1);
printf("1 1");
return;
}
int main(){
int x;
scanf("%d%d", &k, &x);
solve1();
return 0;
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int k;
char stone[305][305];
int main(){
int x;
scanf("%d%d", &k, &x);
for(int i = 1, n = 0; i <= k; ++i)
if(i & 1){
++n;
for(int j = 1; j <= k; ++j)
stone[n][j] = '>';
for(int j = k + 1; j <= 2 * k; j += 2){
stone[n][j] = '.';
stone[n][j + 1] = '>';
}
stone[n][k + k] = 'v';
++n;
for(int j = 2 * k; j > k + 1; --j)
stone[n][j] = '<';
for(int j = k + 1; j > 0; j -= 2){
stone[n][j] = '.';
stone[n][j - 1] = '<';
}
stone[n][1] = '^';
}
else{
++n;
for(int j = 2 * k; j > k; --j)
stone[n][j] = '<';
for(int j = k; j > 0; j -= 2){
stone[n][j] = '.';
stone[n][j - 1] = '<';
}
stone[n][1] = 'v';
++n;
for(int j = 1; j < k; ++j)
stone[n][j] = '>';
for(int j = k; j <= 2 * k; j += 2){
stone[n][j] = '.';
stone[n][j + 1] = '>';
}
stone[n][k + k] = '^';
}
for(int i = 1; i <= 2 * k; ++i){
for(int j = 1; j <= 2 * k; ++j)
putchar(stone[i][j]);
putchar('\n');
}
printf("1 1\n");
return 0;
}
浙公网安备 33010602011771号