1. 程式人生 > 其它 >【題解】[JOI Open 2021] Monster Game

【題解】[JOI Open 2021] Monster Game

麻了,並不知道自適應互動器怎麼實現的/kk,但是題目還是可以想的(

最開始想直接 std::sort 一遍,事實上這個 \(<\) 沒有傳遞性,會返回各種奇奇怪怪的結果。

事實上這是非常神仙的結論題。

結論:直接歸併排序之後的陣列滿足 \(a_i - a_{i + 1} \le 1\)​。

並不知道出題人怎麼想到這個神奇的性質,但知道結論後,我們不難直接遞迴歸納證明。

擁有這個性質的陣列並不少見,因為換一種表述,初始陣列為 \(0\sim N-1\),然後將原陣列分為若干段,每一段取反即可。

所以我們知道前 \(i\) 段的端點,就可以知道第 \(i + 1\) 段的斷點。問題轉化為找到 \(0\)

的位置。

由於 \(0\) 只會比 \(1\) 小,所以在歸併時候,一直在往前跳,感性理解一下。所以排序後 \(0\) 的位置在前 \(\log N\) 個之內。

\(\log N\) 很小,我們直接用 \(N^2\) 演算法求出 \(0\) 的位置即可。

/*
    Author : SharpnessV
    Right Output ! & Accepted !
*/
#include<bits/stdc++.h>
#include"monster.h"
//#define int long long
using namespace std;

#define rep(i, a, b) for(int i = (a);i <= (b);i++)
#define pre(i, a, b) for(int i = (a);i >= (b);i--)
#define rp(i, a) for(int i = 1; i <= (a); i++)
#define pr(i, a) for(int i = (a); i >= 1; i--)
#define go(i, x) for(auto i : x)

#define pb push_back


std::vector<int> a, b, c;

void msort(int l,int r){
	if(l == r)return ;
	int mid = (l + r) >> 1, j = l;
	msort(l, mid), msort(mid + 1, r);
	b.clear();
	rep(i, mid + 1, r){
		while(j <= mid && !Query(a[j], a[i]))b.pb(a[j ++]);
		b.pb(a[i]);
	}
	while(j <= mid)b.pb(a[j ++]);
	rep(i, l, r)a[i] = b[i - l];
}
int cnt[20];
std::vector<int> Solve(int N) {
	
	a.resize(N), b.resize(N), c.resize(N);
  	rp(i, N)a[i - 1] = c[i - 1] = i - 1;
	msort(0, N - 1);
	int n = std::min(20, N);
	
	rep(i, 0, n - 1)rep(j, i + 1, n - 1)
		if(Query(a[i], a[j]))cnt[i]++;
		else cnt[j]++;
	int ed = ~0, pre = 0;
	rep(i, 0, n - 1)if(!cnt[i])ed = i;
	if(-1 == ed){
		int p = 0, q = 0;
		rep(i, 0, n - 1)if(1 == cnt[i])q = i, std::swap(p, q);
		if(Query(a[p], a[q]))ed = p;else ed = q;
	}
	
	//cout<< "ss "<<ed << endl; 
	//rep(i, 0, N - 1)printf("%d ",a[i]);putchar('\n');
	reverse(c.begin(), c.begin() + ed + 1);
	rep(k, ed + 1, N - 1){
		if(Query(a[pre], a[k]))
			reverse(c.begin() + ed + 1, c.begin() + k + 1), pre = ed + 1, ed = k;//, cout << "ww " << k <<endl;
	}
	//rep(i, 0, N - 1)printf("%d ",c[i]);putchar('\n');
	rep(i, 0, N - 1)b[a[i]] = c[i];
	//rep(i, 0, N - 1)printf("%d ",b[i]);putchar('\n');
	return b;
}
/*
g++ monster.cpp grader.cpp -o cur -std=c++14
*/