CF1893A题解报告
五年级蒟蒻的第六篇题解,望通过。
正着操作你就会发现,每个不动点会变到数组的最后一个,但正着不好做,我们就反着来。
首先我们知道操作就是回退 \(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;
}