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}\),那么其发出的响声次数就为:

\[(2x^2 - x) \times \lfloor \frac{x}{2} \rfloor \]

也是能稳过的。

代码实现

点击查看代码
#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;
}
posted @ 2023-11-22 17:19  静观默察  阅读(17)  评论(0)    收藏  举报