結果
問題 | No.2382 Amidakuji M |
ユーザー |
|
提出日時 | 2023-07-14 23:26:38 |
言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 49 ms / 2,000 ms |
コード長 | 4,351 bytes |
コンパイル時間 | 8,977 ms |
コンパイル使用メモリ | 277,500 KB |
最終ジャッジ日時 | 2025-02-15 14:47:04 |
ジャッジサーバーID (参考情報) |
judge2 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 19 |
ソースコード
#line 2 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/template/procon.hpp"#ifndef DEBUG// 提出時にassertはオフ#ifndef NDEBUG#define NDEBUG#endif// 定数倍高速化#pragma GCC target("avx2")#pragma GCC optimize("O3")#pragma GCC optimize("unroll-loops")#endif#include <bits/stdc++.h>using namespace std;using ll = long long;using i64 = long long;using u64 = unsigned long long;#define ALL(x) (x).begin(), (x).end()template <class T>using vec = vector<T>;template <class T, class S>inline bool chmax(T &a, const S &b) {return (a < b ? a = b, 1 : 0);}template <class T, class S>inline bool chmin(T &a, const S &b) {return (a > b ? a = b, 1 : 0);}template <class T>constexpr T INF = 1'000'000'000;template <>constexpr int INF<int> = 1'000'000'000;template <>constexpr ll INF<ll> = ll(INF<int>) * INF<int> * 2;#line 3 "/home/cocojapanpan/Procon_CPP/proconLibrary/lib/data-structure/DualSegmentTree.hpp"// 区間更新、一点取得を行う ただし作用は可換(RUQならタイムスタンプを付けるなどする)// つまり区間更新を通常のセグ木の区間取得と同様に行うtemplate <class CommutativeMap>class DualSegTree {// CommutativeMap::S 要素の型// CommutativeMap::F 作用の型// CommutativeMap::mapping S(F f, S x) 要素xに作用fを作用させる// CommutativeMap::id F() 恒等写像// CommutativeMap::composition F(F f, F g) 作用の合成 可換!using M = CommutativeMap;using F = typename M::F;using S = typename M::S;static_assert(std::is_convertible_v<decltype(&M::mapping), std::function<S (F, S)>>, "mapping S(F, S) type error");static_assert(std::is_convertible_v<decltype(&M::id), std::function<F()>>, "id F() type error");static_assert(std::is_convertible_v<decltype(&M::composition), std::function<F (F, F)>>,"composition F(F, F) type error");public:explicit DualSegTree(int _N, const S& init) : N(_N), data(_N, init) {leaf = 1;while(leaf < N) {leaf <<= 1;}lazy.assign(leaf * 2, M::id());}// data[p] = xvoid set(int p, const S& x) {assert(0 <= p && p < N);data[p] = x;}// 区間[l, r)に作用fを適用void apply(int l, int r, const F & f) {assert(0 <= l && l <= r && r <= N);// logN個のlazyノードに分配l += leaf; r += leaf;while(l < r) {if(l & 1) {lazy[l] = M::composition(lazy[l], f);++l;}if(r & 1) {--r;lazy[r] = M::composition(lazy[r], f);}l >>= 1;r >>= 1;}}// a[p]を取得 上のノードlogN個を作用させて返すS get(int p) const {assert(0 <= p && p < N);int index = p + leaf;F fmap = M::id();while(index > 0) {fmap = M::composition(fmap, lazy[index]);index >>= 1;}return M::mapping(fmap, data[p]);}private:const int N; // 考える要素数vec<F> lazy; // 可換な写像の完全二分木vec<S> data; // 実際の値int leaf; // 葉の数};#line 3 "main.cpp"struct rangeAddOne {using S = int;using F = int;static S mapping(F f, S x) {return f + x;}static F id() {return 0;}static F composition(F f, F g) {return f + g;}};int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);int N;ll M;cin >> N >> M;vec<int> P(N);for(int &p : P) {cin >> p;--p;}vec<int> numToID(N);for(int i = 0; i < N; i++) {numToID[P[i]] = i;}DualSegTree<rangeAddOne> dual(N, 0);// まず最小の回数を数えるll cnt = 0;for(int i = 0; i < N; i++) {cnt += dual.get(numToID[i]) + numToID[i] - i;dual.apply(0, numToID[i], 1);}ll ans = -1;if(cnt == 0) {ans = 0;} else {ll smallestM = (cnt + M - 1) / M * M;if((smallestM - cnt) % 2 == 0) {ans = smallestM;} else if((smallestM + M - cnt) % 2 == 0) {ans = smallestM + M;}}cout << ans << "\n";}