给定
考虑卡片之间的联系,显然若一个数在同一张卡牌的正反面那么这张卡牌必须选择,否则无法凑齐一个排列,反之这个数一定会在两张卡牌中出现,且这两张卡牌一定至少有一张被选择,否则依然无法凑齐一个排列,这个很好理解。
于是我们考虑一些对于这种题的一般的套路,可以尝试建图,对于本题不难想到,我们将一张卡牌作为一个点,将这个点向卡牌上存在的数的另一次出现所在的卡牌连一条边。抽象地说,对于一个数所在的两张(或一张)卡牌位置
不难想到这样会形成多个环,每一个环代表着其中几张卡牌,同时这些卡牌上的数在环内一定每个数都出现了两遍,如排列
同时发现不同环的方案数,只跟环的长度有关,于是我们考虑令
于是考虑并查集维护好每个环的大小,
xxxxxxxxxx
781
2
3
4
5
6
7
8
9
10
11using namespace std;
12using namespace __gnu_pbds;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25template< typename T = int >
26inline T read(void);
27
28int N;
29int P[210000], Q[210000];
30int cnt[210000];
31int pos[210000][2];
32int f[210000];
33bool vis[210000];
34int ans(1);
35
36class UnionFind{
37private:
38public:
39 int fa[210000];
40 int siz[210000];
41 UnionFind(void){for(int i = 1; i <= 201000; ++i)fa[i] = i, siz[i] = 1;}
42 int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
43 void Union(int origin, int son){
44 if(Find(origin) == Find(son))return;
45 siz[Find(origin)] += siz[Find(son)], fa[Find(son)] = Find(origin);
46 }
47}uf;
48
49int main(){
50 N = read();
51 f[1] = 1, f[2] = 3;
52 for(int i = 3; i <= N; ++i)f[i] = (ll)(f[i - 1] + f[i - 2]) % MOD;
53 for(int i = 1; i <= N; ++i)P[i] = read(), pos[P[i]][cnt[P[i]]++] = i;
54 for(int i = 1; i <= N; ++i)Q[i] = read(), pos[Q[i]][cnt[Q[i]]++] = i;
55 for(int i = 1; i <= N; ++i)
56 uf.Union(i, pos[P[i]][0] ^ pos[P[i]][1] ^ i),
57 uf.Union(i, pos[Q[i]][0] ^ pos[Q[i]][1] ^ i);
58 for(int i = 1; i <= N; ++i)if(uf.Find(i) == i)ans = (ll)ans * f[uf.siz[uf.Find(i)]] % MOD;
59 printf("%d\n", ans);
60 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
61 return 0;
62}
63
64template < typename T >
65inline T read(void){
66 T ret(0);
67 short flag(1);
68 char c = getchar();
69 while(c != '-' && !isdigit(c))c = getchar();
70 if(c == '-')flag = -1, c = getchar();
71 while(isdigit(c)){
72 ret *= 10;
73 ret += int(c - '0');
74 c = getchar();
75 }
76 ret *= flag;
77 return ret;
78}
update-2022_10_25 初稿