トピックリンク:ナンバープレート
一般的なアイデア
nnの長さが与えられたn 、 iiのシーケンスi位置aia_ia私は。(保証されたaaaは111〜nn _ _nの順列
各位置には値did_iもありますd私は, 若满足 ∣ i − j = d i ∣ |i-j=d_i| ∣ i−j=d私は∣、位置iiiと位置jjjは何度でも交換できます
Q:最終シーケンスはai = i a_i=iを満たすことができますかa私は=i。
問題解決のアイデア
とチェック (データが小さすぎる、ゲーム中にフロイドが書かれた)
2つのポジション間の交換の数は任意であるため。したがって、xxの場合x和yyyは交換可能で、yyy和ズ_zを交換してから、x、y、zx、y、zをx 、および、3つの位置でzaaaの値は交換可能です。
上記の分析は、有限サイズの連結集合に一般化できます。
したがって、接続された各セットの内部aia_iを判断するだけで済みます。a私は値が設定された添え字と同じかどうかii私は同じになることができます。
フロイド
set mp [] mp []m p [ ]、ここでmp [val] mp [val]m p [ v a l ] recordval valvalの要素が配置されている元のシーケンスの
問題の性質を考慮します。ai≠ia_i\neiがある場合a私は。=i 、 iiを示すiの位置はmp[a[i]] mp[a[i]]と同じである必要がありますmp [ a [ i ] ]の位置が交換されます。つまり、 i、ji、j私、jの2つの位置に到達できるかどうか。複数のソースの最短経路を処理を考える方が簡単
この問題は2点間の距離を見つける必要がないことを考えると、到達可能かどうかを判断するだけでよいので、FloydFloydを使用する場合F l o y dアルゴリズム、ループの3番目の層は和集合と見なすことがビットを渡すことができます最適化するためにbit set。
この練習を書いていると、私は主にこの質問がビットセットビットセットであると感じていますb i t s e tOptimizing F loydFloydF l oydの紹介の質問は友好的です。
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;
}
フロイド+ビットセット
#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;
}