错题本 (并查集) acwing 4084.号码牌
題目鏈接
題目描述
有 nnn 個(gè)小朋友,編號(hào) 1~n1~n1~n。
每個(gè)小朋友都拿著一個(gè)號(hào)碼牌,初始時(shí),每個(gè)小朋友拿的號(hào)碼牌上的號(hào)碼都等于其編號(hào)。
每個(gè)小朋友都有一個(gè)幸運(yùn)數(shù)字,第 iii 個(gè)小朋友的幸運(yùn)數(shù)字為 did_idi?。
對(duì)于第 iii 個(gè)小朋友,他可以向第 jjj 個(gè)小朋友發(fā)起交換號(hào)碼牌的請(qǐng)求,當(dāng)且僅當(dāng) ∣i?j∣=di|i?j|=d_i∣i?j∣=di? 成立。
注意,請(qǐng)求一旦發(fā)出,對(duì)方無法拒絕,只能立刻進(jìn)行交換。
每個(gè)小朋友都可以在任意時(shí)刻發(fā)起任意多次交換請(qǐng)求。
給定一個(gè) 1~n1~n1~n 的排列 a1,a2,…,ana1,a2,…,ana1,a2,…,an。
請(qǐng)問,通過小朋友相互之間交換號(hào)碼牌,能否使得第 i 個(gè)小朋友拿的號(hào)碼牌上的號(hào)碼恰好為 aia_iai?,對(duì) i∈[1,n]i∈[1,n]i∈[1,n] 均成立。
輸入格式
第一行包含整數(shù) n。
第二行包含 n 個(gè)整數(shù) a1,a2,…,ana1,a2,…,ana1,a2,…,an。
第三行包含 n 個(gè)整數(shù) d1,d2,…,dnd1,d2,…,dnd1,d2,…,dn。
輸出格式
共一行,如果能做到,則輸出 YES,否則輸出 NO。
數(shù)據(jù)范圍
所有測(cè)試點(diǎn)滿足 1≤n≤100,1≤di≤n,保證 a1~an 是一個(gè) 1~n 的排列。
樣例
輸入樣例1:
5 5 4 3 2 1 1 1 1 1 1輸出樣例1:
YES
輸入樣例2:
7 4 3 5 1 2 7 6 4 6 6 1 6 6 1輸出樣例2:
NO
分析:
聯(lián)通塊(并查集)
交換方式唯一,說白了就是一個(gè)可以互相交換的小團(tuán)體翻來覆去的換,可以交換達(dá)到的任意兩點(diǎn)絕對(duì)可達(dá)
- 考慮以聯(lián)通塊編號(hào)為數(shù)組下標(biāo),構(gòu)建一個(gè)聯(lián)通塊內(nèi)可達(dá)點(diǎn)集
- 同樣以下邊所在聯(lián)通塊編號(hào)為下標(biāo),標(biāo)注一個(gè)題目要求達(dá)的點(diǎn)集,比較集合相等即可
code
#include<bits/stdc++.h> using namespace std; const int N = 1e3+9; vector <int> A[N],B[N]; int fa[N], a[N] , d[N];int find (int x) {if(fa[x]==x) return x;else return fa[x]= find(fa[x]); }int main() {int n;scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d",&a[i]);for (int i = 1; i <= n; i ++ ) scanf("%d",&d[i]);for (int i = 1; i <= n; i ++ ) fa[i] =i;for (int i = 1; i <= n; i ++ ){if(i+d[i]<=n) fa[find (i+d[i])] =find (i);if(i-d[i]>=1) fa[find (i-d[i])] =find (i);}for (int i = 1; i <= n; i ++ ){A[find (i)].push_back (i);B[find (i)].push_back (a[i]);}for (int i = 1; i <=n; i ++ ){sort (B[i].begin(),B[i].end());if(A[i]!=B[i]){puts ("NO");return 0;}}puts("YES");return 0; }總結(jié)
以上是生活随笔為你收集整理的错题本 (并查集) acwing 4084.号码牌的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 继明哥的否定之后,java泰又出新作!明
- 下一篇: 手游立项(一):理解手游开发