题目链接:https://codeforces.com/problemset/problem/1770/D
大致题意:有三个数组,每个数组的长度为n,数组里面的每个数在(1-n)。现在,对于每一位上面的数,Mahiru可以去掉其中一个数组里面的数;
然后,Koxia会从剩下俩个数里面选择一个。最终,Koxia会得到一个数组,如果这个数组是一个序列,那么Koxia赢。
题目给出其中俩个数组,要求我们计算,会有多少种情况的第三个数组,使得Koxia会赢;
解题思路:首先,我们来考虑每一位上的a和b的关系;
1:如果a==b
容易知道,如果a==b,那么无论c数组是什么Koxia都可以取到a这个数,这个时候,
如果最终的序列里面要求这个位置为a,那么c可以取(1-n),所以贡献为n;
而如果最终序列里面要求这个位置是所选的c,那么Mahiru可以去掉c这个数,所以这种情况的贡献为0;
2:如果a!=b
由以上1的分析可以知道,要想Mahiru不管去掉哪个数,Koxia都可以取到自己想选的数的话,那么c必然与a,b中的一个相同;
故c只有a和b俩种情况,贡献为2;
那难道这就是结果了吗?不不不!
我们应该想到,c从a和b里面选择了一个,假设c选a,那么后面必然需要一个位置选b,假设那个位置的另外一个数为d,那么后面必然有一个位置选d.......
由此,我们应该想到,对于a!=b这种情况来看的话,必然会出现一个类似与选c的序列为abdef.........xyza,这样子的环,而判断这样子的环,当然是用并查集来的方便;
那么我们的思路就这样子出来了,一开始ans = 1,如果该位置是1的情况,那么ans*=n;
如果不是,那么我们就把这俩个数放在一个并查集里面,直到到环的结尾,我们就ans*=2;
当然,还存在着ans == 0的情况,至于判断ans == 0,还请看官细细品味一下的代码即可。
时间复杂度:O(n)(也许应该吧....)
ac代码:
#include<bits/stdc++.h> #define int long long int p[100005]; int mod = 998244353; int FIND(int x) { return p[x] == x ? x : p[x] = FIND(p[x]); } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); int T; std::cin >> T; while (T--) { int n; std::cin >> n; std::vector<int> a(n + 1, 0), b(n + 1, 0); for (int i = 1; i <= n; ++i)std::cin >> a[i], p[i] = i; for (int i = 1; i <= n; ++i)std::cin >> b[i]; int ans = 1; p[n + 1] = n + 1; for (int i = 1; i <= n; ++i) { if (FIND(a[i]) == FIND(b[i]))ans = ((ans % mod) * (a[i] == b[i] ? n : 2ll)) % mod, p[p[a[i]]] = n + 1; else { if (p[a[i]] > p[b[i]])std::swap(a[i], b[i]); p[p[a[i]]] = p[b[i]]; } } //下面即为判断ans==0的情况; for (int i = 1; i <= n; ++i)if (FIND(i) != n + 1) { ans = 0; break; } std::cout << ans << "\n"; } return 0; }
此题对于思维的要求没有太大,重点在于想到并查集,并用并查集来判断ans==0的情况,这个就比较考验对于数据结构的理解程度了:)
标签:std,Good,int,NEAR,Game,那么,数组,ans,Koxia From: https://www.cnblogs.com/ACMER-XiCen/p/17085580.html