バイトの競プロメモ

主に競技プログラミング

キーエンス プログラミング コンテスト 2020 D - Swap and Flip

https://atcoder.jp/contests/keyence2020/tasks/keyence2020_d

 

最終的にひっくり返るカードを決め打つと、最終的な数列が定まります

 

ひっくり返るカードは奇数個移動し、その他のカードは偶数個移動することを考えると

それぞれの移動後のパリティが決まり、基本的に行先が簡単に定まります(作れない場合もあるので判定が必要) 

 

最終的に同じ数が並ぶ場合は例外で、移動前と後で,移動後のパリティと数が同じ数字の前後関係が一致するように動かせばいいです

 

https://atcoder.jp/contests/keyence2020/submissions/9583390

↓下は疑似コードだと思ってください…

#include<bits/stdc++.h>
using namespace std;
#define int long long

using vi = vector<int>;
#define rep(i,n) for (int i = 0; i < n; i++)
#define rer(i,n) for (int i = n; i >= 0; i--)

constexpr bool bget(int m, int keta) {
return (m >> keta) & 1;
}

void solve() {
int N;
cin>>N;
vector<vector<int>> S(2,vi(N));
int best = 1e18;

rep(mas, 1<<N) {
vi A;
//奇数移動 パリティ変更
//bitなら 裏になる
rep(i, N) {
A .push_back(S[bget(mas, i)][i]);
}
vi sa = sorted(A);//ソート後のAを代入
vni(pos, 2, 51, 0);//3次元 要素数は(2 * 51 * 0)
rep(i, N) {
pos[i % 2][sa[i]] .push_back(i);
}
vi inds(N);
//昇順を後ろから見る
rer(f, N - 1) {//[N-1, 0]
int v = A[f];
int pari = f % 2;
pari ^= bget(mas, f);
if (sz(pos[pari][v]) == 0)goto end;
int t = pos[pari][v].back();
pos[pari][v].pop_back();
inds[f] = t;
}
best=min(best, tentousuu(inds));
end:;
}
if (best == 1e18)best = -1;
cout<<best<<endl;
}