【思维构造】Anonymous Informant—CF1894C

Anonymous Informant—CF1894C

翻译

给定一个数组 b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn

一个匿名的消息来源告诉你,数组 b b b 是这样得到的:最初存在一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an,然后进行了以下两步操作共 k k k 次:

  1. 选择数组 a a a 的一个固定点 † ^{\dagger} x x x
  2. 然后,将数组 a a a 循环左移 ‡ ^{\ddagger} 恰好 x x x 次。

经过 k k k 次这样的操作后得到了数组 b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn。你想要检查匿名消息来源的话是否为真,或者它们必定是假的。

† ^{\dagger} 如果 1 ≤ x ≤ n 1 \leq x \leq n 1xn a x = x a_x = x ax=x,则数字 x x x 被称为数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 的一个固定点。

‡ ^{\ddagger} 数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 的循环左移是数组 a 2 , … , a n , a 1 a_2, \ldots, a_n, a_1 a2,,an,a1
输入

每个测试包含多个测试用例。第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1t104) — 测试用例的数量。接下来是测试用例的描述。

每个测试用例的第一行包含两个整数 n , k n, k n,k ( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1n2105, 1 ≤ k ≤ 1 0 9 1 \le k \le 10^9 1k109) — 数组 b b b 的长度和执行的操作次数。

每个测试用例的第二行包含 n n n 个整数 b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn ( 1 ≤ b i ≤ 1 0 9 1 \le b_i \le 10^9 1bi109) — 数组 b b b 的元素。

保证所有测试用例中 n n n 的值的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2105
输出

对于每个测试用例,如果匿名消息来源的话可以为真,则输出 “Yes”,如果它们必定为假,则输出 “No”。
注意

在第一个测试用例中,数组 a a a 可能等于 [ 3 , 2 , 3 , 4 , 3 ] [3, 2, 3, 4, 3] [3,2,3,4,3]。在第一次操作中,选择了一个固定点 x = 2 x = 2 x=2,经过 2 2 2 次左移后,数组变为 [ 3 , 4 , 3 , 3 , 2 ] [3, 4, 3, 3, 2] [3,4,3,3,2]。在第二次操作中,选择了一个固定点 x = 3 x = 3 x=3,经过 3 3 3 次左移后,数组变为 [ 3 , 2 , 3 , 4 , 3 ] [3, 2, 3, 4, 3] [3,2,3,4,3]。在第三次操作中,再次选择了一个固定点 x = 3 x = 3 x=3,经过 3 3 3 次左移后,数组变为 [ 4 , 3 , 3 , 2 , 3 ] [4, 3, 3, 2, 3] [4,3,3,2,3],与数组 b b b 相等。

在第二个测试用例中,数组 a a a 可能等于 [ 7 , 2 , 1 ] [7, 2, 1] [7,2,1]。在固定点 x = 2 x = 2 x=2 的操作后,数组变为 [ 1 , 7 , 2 ] [1, 7, 2] [1,7,2]。然后,在固定点 x = 1 x = 1 x=1 的操作后,数组回到了初始状态 [ 7 , 2 , 1 ] [7, 2, 1] [7,2,1]。这两个操作( x = 2 x = 2 x=2 x = 1 x = 1 x=1)被重复了 49 49 49 次。因此,在 100 100 100 次操作后,数组回到了 [ 7 , 2 , 1 ] [7, 2, 1] [7,2,1]

在第三个测试用例中,可以证明没有解决方案。

思路

注意,题目没有要求数组 a a a 与数组 b b b 是相等的!不要被前两个样例给迷惑了。

很容易能够看出,在某一次操作中如果选择 a x a_x ax 为固定点(其中 1 ≤ x ≤ n 1 \le x \le n 1xn a x = x a_x=x ax=x),那么在将 a a a 数组左移 x x x 位后的新 a ′ a' a 数组的最后一个元素 a n ′ a_n' an 一定是原来的 a x a_x ax

由于 b b b 是操作后得到的数组,所以我们可以倒着模拟这个操作过程。因为 a x a_x ax 在操作后一定变成了最后一个元素,所以我们可以维护操作过程中的最后一个元素在 b b b 数组中的下标,记作 l a s t last last。如果 b l a s t > n b_{last}>n blast>n,那么很显然这时的 a a a 数组不能由之前的 a a a 数组得到(因为不满足固定点的定义,不能进行操作),输出 No

如果操作可以进行 n n n 次,那么就一定会进入循环之中,所以无需模拟 k k k 次,只需 m i n ( k , n ) min(k, n) min(k,n)。当然,上述的操作如果可以进行了 m i n ( k , n ) min(k, n) min(k,n) 次,就可以输出 Yes

模拟的过程是重点,需要看着代码自己理解。文字并不好描述。

#include 
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;

int n, k;

void solve(int Case) {
	cin >> n >> k;
	vector<int> b(n + 1);
	for (int i = 1; i <= n; i ++) cin >> b[i];
	
	int last = n;
	k = min(k, n);
	while (k --) {
		if (b[last] > n) {
			cout << "No\n";
			return;
		}
		last += (n - b[last]);
		if (last > n) {
			last -= n;
		}
	}
	cout << "Yes\n";
}

signed main() {
	cin.tie(0)->ios::sync_with_stdio(false);
	int T = 1;
	cin >> T; cin.get();
	int Case = 0;
	while (++ Case <= T) solve(Case);
	return 0;
}

你可能感兴趣的:(思维构造,c++)