九校联考-长沙市一中NOIP模拟Day1T2 跳房子(jump)

问题描述

跳房子,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。
跳房子是在N个格子上进行的,CYJ对游戏进行了改进,该成了跳棋盘,改进后的游戏是在一个N行M列的棋盘上进行,并规定从第一行往上可以走到最后一行,第一列往左可以走到最后一列,反之亦然。每个格子上有一个数字。
在这个棋盘左上角(1,1)放置着一枚棋子。每次棋子会走到右、右上和右下三个方向格子中对应上数字最大一个。即任意时刻棋子都只有一种走法,不存在多个格子同时满足条件。
现在有两种操作:
move k 将棋子前进k步。
change a b e 将第a行第b列格子上的数字修改为e。
请对于每一个move操作输出棋子移动完毕后所处的位置。

输入

第一行包含两个正整数N,M(3<=N,M<=2000),表示棋盘的大小。
接下来N行,每行M个整数,依次表示每个格子中的数字ai,j
接下来一行包含一个正整数Q(1<=Q<=5000),表示操作次数。
接下来m行,每行一个操作,其中1<=a<=N,1<=b<=M,1<=k,e<=109。

输出

对于每个move操作,输出一行两个正整数x,y,即棋子所处的行号和列号。

输入输出样例

样例输入

4 4
1 2 9 3
3 5 4 8
4 3 2 7
5 8 1 6
4
move 1
move 1
change 1 4 100
move 1

样例输出

4 2
1 3
1 4

数据范围

10%的数据满足:3<= N,M <=50,Q<=5000, k<=10;
20%的数据满足:3<= N,M <=200,Q<=5000,k<=5000;
另有20%的数据满足:3<= N,M <=200,Q<=5000,k<=109;
100%的数据满足:3<= N,M <=2000,Q<=5000,e,k<=109;

记录第一列第i行能走到位置jump[i],询问时一行一行的走,不足一行时一步一步走,修改时暴力重构jump数组
看起来很像分块???
代码

#include <cstdio>
#include <limits>

#define MAX 2000

int R, C;
int a[MAX][MAX];
int pos_r = 0, pos_c = 0;
int jump[MAX];

int Fix(int x, int X) {
  return (x % X + X) % X;
}

int NextRow(int r, int c) {
  int next_row = -1;
  int max_value = -1;
  for (int rr = r - 1; rr <= r + 1; ++rr) {
    const int value = a[Fix(rr, R)][Fix(c + 1, C)];
    if (value > max_value) {
      max_value = value;
      next_row = rr;
    }
  }
  return next_row;
}

int RunToFirstColumn(int r, int c) {
  do {
    r = Fix(NextRow(r, c++), R);
  } while (c < C);
  return r;
}

struct Interval {
  Interval() = default;
  Interval(int lo, int hi) : lo(lo), hi(hi) {}
  bool IsEmpty() const { return lo > hi; }
  int Size() const { return hi - lo + 1; }
  bool Contains(int x) const { return lo <= x && x <= hi; }
  int lo = std::numeric_limits<int>::max();
  int hi = std::numeric_limits<int>::min();
};

void Update(int r, int c) {
  const int target_row = RunToFirstColumn(r, c);
  Interval rows(r, r);
  int cc = c;
  while (cc > 0) {
    --cc;
    Interval new_rows; 
    for (int rr = rows.lo - 1; rr <= rows.lo + 1; ++rr) {
      if (rows.Contains(NextRow(rr, cc))) {
        new_rows.lo = rr;
        break;
      }
    }
    for (int rr = rows.hi + 1; rr >= rows.hi - 1; --rr) {
      if (rows.Contains(NextRow(rr, cc))) {
        new_rows.hi = rr;
        break;
      }
    }
    if (new_rows.IsEmpty()) return;
    rows = new_rows;
  }
  if (rows.Size() >= R) {
    for (int rr = 0; rr < R; ++rr) {
      jump[rr] = target_row;
    }
  } else {
    for (int rr = rows.lo; rr <= rows.hi; ++rr) {
      jump[Fix(rr, R)] = target_row;
    }
  }
  return;
}

void SuperWalk(int k) {
  static int walk_id = 0;
  static int last_walk_id[MAX];
  static int last_k[MAX];
  ++walk_id;
  
  if (k >= C - pos_c) {
    k -= C - pos_c;
    pos_r = RunToFirstColumn(pos_r, pos_c);
    pos_c = 0;
  }
  while (k >= C) {
    k -= C;
    pos_r = jump[pos_r];

    if (last_walk_id[pos_r] == walk_id) {
      const int cycle_len = last_k[pos_r] - k;
      if (k >= cycle_len) {
        const int n_cycles = k / cycle_len;
        k -= n_cycles * cycle_len;
      }
    }
    last_walk_id[pos_r] = walk_id;
    last_k[pos_r] = k;
  }
  while (k--) {
    pos_r = Fix(NextRow(pos_r, pos_c++), R);
  }
}

int main() {
  scanf("%d%d", &R, &C);
  for (int r = 0; r < R; ++r) {
    for (int c = 0; c < C; ++c) {
      int k;
      scanf("%d", &k);
      a[r][c] = k;
    }
  }
  for (int r = 0; r < R; ++r) {
    jump[r] = RunToFirstColumn(r, 0);
  }

  int Q;
  scanf("%d", &Q);
  for (int qq = 0; qq < Q; ++qq) {
    static char command[16];
    scanf("%s", command);
    if (command[0] == 'm') {
      int k;
      scanf("%d", &k);
      SuperWalk(k);
      printf("%d %d\n", pos_r + 1, pos_c + 1);
    } else {
      int r, c, k;
      scanf("%d%d%d", &r, &c, &k); --r; --c;
      a[r][c] = k;
      for (int rr = r - 1; rr <= r + 1; ++rr) {
        Update(Fix(rr, R), Fix(c - 1, C));
      }
    }
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/shulker/p/9656427.html