A. Anonymous Informant
题面:
链接:https://codeforces.com/problemset/problem/1893/A
洛谷链接:https://www.luogu.com.cn/problem/CF1893A
思路:逆着推
有一个非常重要的结论得观察出来:
所以当倒过来推的时候(b->a),同理可以直接取b的最后一个:拿b[x]的值往前跳,跳到的指针就是原来a的最后一个
所以不用dfs,因为每次必然会有最后一个的产生。
如何剪枝?很显然,如果多次访问到一个位置,那么说明产生了循环,则肯定可以,直接break就行,所以最坏的复杂度在O(n)
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#include<set>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
ll b[N];
bool vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)
{
ll n, k; cin >> n >> k;
for (int i = 0; i < n; i++)cin >> b[i];
ll ptr = n - 1;
memset(vis, 0, sizeof(vis));
bool al = true;
for (int i = 0; i < k; i++)
{
if (b[ptr] > n)
{
al = false; break;//如果某个数比n都大,那么肯定不行
}
else
{
vis[ptr] = 1;//标记vis
ptr = (n + ptr - b[ptr]) % n;//往前跳,加n求余防越界
if (vis[ptr])break;//剪枝
}
}
if (al)cout << "Yes";
else cout << "No";
cout << '\n';
}
return 0;
}
rt,有点巧妙!