AcWing4084 号码牌 (并查集 / bitset优化Floyd)
題目鏈接: 號碼牌
大致題意
給定一個長度為nnn的序列, 第iii個位置的值為aia_iai?. (保證aaa是111~nnn的一個排列)
每個位置還有一個值did_idi?, 若滿足∣i?j=di∣|i-j=d_i|∣i?j=di?∣, 表示位置iii和位置jjj可以進行任意次交換.
問: 能否使得最終的序列滿足ai=ia_i = iai?=i.
解題思路
并查集 (數據太小了, 比賽時寫了個Floyd)
由于兩個位置的交換次數是任意次. 因此, 如果xxx和yyy可以交換, 且yyy和zzz可以交換, 則x,y,zx, y, zx,y,z三個位置處的aaa值可以互換.
上述分析可以推廣到一個有限大小的連通集合中.
因此, 我們只需要判斷每個連通集合內部aia_iai?值是否和該集合下標iii相同即可.
Floyd
設mp[]mp[]mp[], 其中mp[val]mp[val]mp[val]記錄valvalval元素所處原序列的位置.
我們考慮題目的本質: 如果有ai≠ia_i \ne iai??=i, 表明iii位置需要與mp[a[i]]mp[a[i]]mp[a[i]]位置進行交換. 即: 我們需要判斷i,ji, ji,j兩個位置是否可達. 我們比較容易想到通過多源最短路進行處理.
考慮到本題并不需要求出兩點的距離, 只需要判斷是否可達, 因此若采用FloydFloydFloyd算法, 第三層循環可以認為是在求并集, 我們可以通過bitsetbitsetbitset進行優化.
寫上這個做法, 主要感覺這個題作為bitsetbitsetbitset優化FloydFloydFloyd入門題很友好.
AC代碼
并查集DSU
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; const int N = 1E2 + 10; int a[N], d[N];/* 并查集模版 */ struct DSU {int p[N];int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }void merge(int a, int b) {a = find(a), b = find(b);if (a == b) return;p[b] = a;}void init(int n) { rep(i, n) p[i] = i; } }dsu;vector<int> v1[N], v2[N]; int main() {int n; cin >> n;rep(i, n) scanf("%d", &a[i]);rep(i, n) scanf("%d", &d[i]);dsu.init(n);rep(i, n) {int x = i - d[i], y = i + d[i];if (x >= 1) dsu.merge(i, x);if (y <= n) dsu.merge(i, y);}rep(i, n) v1[dsu.find(i)].push_back(a[i]), v2[dsu.find(i)].push_back(i);bool flag = 1;rep(i, n) {if (i != dsu.find(i)) continue;sort(v1[i].begin(), v1[i].end());if (v1[i] != v2[i]) flag = 0;}puts(flag ? "YES" : "NO");return 0; }Floyd + bitset
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; const int N = 1E2 + 10; int a[N], d[N], mp[N]; bitset<N> can[N];void fact(int a, int b) { can[a][b] = can[b][a] = 1; } int main() {int n; cin >> n;rep(i, n) scanf("%d", &a[i]), mp[a[i]] = i;rep(i, n) {scanf("%d", &d[i]);if (i - d[i] > 0) fact(i, i - d[i]);if (i + d[i] <= n) fact(i, i + d[i]);can[i][i] = 1;}rep(k, n) rep(i, n) {if (can[i][k]) can[i] |= can[k];}bool flag = 1;rep(i, n) flag &= can[i][mp[i]];puts(flag ? "YES" : "NO");return 0; }END
總結
以上是生活随笔為你收集整理的AcWing4084 号码牌 (并查集 / bitset优化Floyd)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node.js中公培训笔记大全(讲的一般
- 下一篇: 网络面试题:字节序?网络字节序和主机字节