CF1893A题解报告

五年级蒟蒻的第六篇题解,望通过。

题目传送门CF

正着操作你就会发现,每个不动点会变到数组的最后一个,但正着不好做,我们就反着来。

首先我们知道操作就是回退 \(b_n\) 格,由上面的发现得到。那么问题就变成了 \(b\) 数组能不能操作 \(k\) 次。

不难发现,当 \(b_n > n\) 时,无法继续操作。所以考虑模拟操作。

其实每次模拟不一定要回退整个数组,只需要维护当前的最后一个在原数组的哪里即可。用 \(now\) 表示,经过推算就知道 \(now = (now - b_{now} + n - 1) \bmod n\)

我们发现 \(k\) 很大,显然不能枚举所有操作。我们发现如果当前的 \(now\) 在以前出现过,那么将会进入循环。因为对于每次修改 \(now\),这次的 \(now, a_{now}, n\) 跟上次的 \(now, a_{now}, n\) 一模一样,导致后续过程完全相同,所以会进入循环。考虑标记每个 \(now\) 是否出现过,就可以在重复时退出循环,操作次数就变为了 \(\le n\),时间复杂度为 \(O(\sum n)\)

code

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 1;

int t, n, k, a[N], now;
bool v[N];

bool Solve(){
  cin >> n >> k;
  for(int i = 1; i <= n; i++) cin >> a[i];
  now = n;
  fill(v + 1, v + n + 1, 0);
  while(k-- && !v[now]){
    v[now] = 1;
    int x = a[now];
    if(x > n) return 0;
    now = (now - x + n - 1) % n + 1;
  }
  return 1;
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> t;
  while(t--){
    cout << (Solve() ? "Yes" : "No") << '\n';
  }
  return 0;
}
posted @ 2026-02-02 21:30  tangtianyao0123  阅读(2)  评论(0)    收藏  举报