目錄
- 題目概述
- 思路想法
- 參考程式碼
- 做題反思
題目概述
原題參考:B. Informatics in MAC
給出一個長度為n的陣列,問是否可以將其分為k個(k>1)mex相同的陣列,如果可以的話,作出一種劃分
思路想法
假設一個陣列可以被分為k(k>2)個區間,每個區間的mex相同,那麼可以確定的是,該陣列中一定不存在mex這個數,假設存在mex,那麼mex無論劃分到任意區間,那麼該區間的mex都不可能是mex;因此,我們可以知道陣列中不存在mex元素,因此假如可以將陣列劃分為k(k>2)個區間,那麼也可以將陣列劃分為2個區間,這兩個區間的mex相同,那麼只需要對陣列分別正向和逆向求一遍mex即可
如何快速的求mex,已知mex是一段區間中未出現的最小正整數,也就是說,可以將該區間分為兩部分(以上),也就是說,該區間是不連續的,求解連續性問題,很容易想到並查集
,那麼對於並查集的初始化就是每個點只能連結自己,當出現某一點時,可以知道,mex不可能是她,也就是說,他和下一位連結起來了,對於每次求當前區間的mex,只需要找到從0開始的最遠的區間即可
參考程式碼
#include <bits/stdc++.h>
using namespace std;
#define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define pll pair<long long, long long>
#define pii pair<int, int>
#define vi vector<int>
#define vl vector<long long>
#define ll long long
#define ull unsigned long long
const ll INF = 9187201950435737471;
const int inf = 2139062143;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int N = 2e5+7;
int n, a[N], mmax = 0;
struct DSU {
int fa[N];
DSU(int n) {for(int i=0; i<=n; i++) fa[i] = i;}
void init(int n) {for(int i=0; i<=n; i++) fa[i] = i;}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
};
void solve() {
int lt[N], rt[N];
cin >> n;
for(int i=1; i<=n; i++) cin >> a[i], mmax = max(mmax, a[i]);
DSU k(mmax+5);
for(int i=1; i<=n; i++) {
k.fa[a[i]] = k.find(a[i]+1);
lt[i] = k.find(0);
}
k.init(mmax+5);
for(int i=n; i; i--) {
k.fa[a[i]] = k.find(a[i]+1);
rt[i] = k.find(0);
}
int ans = -1;
for(int i=1; i<=n-1; i++) {
if(lt[i] == rt[i+1]) {
ans = i;
break;
}
}
cout << (ans == -1 ? -1 : 2) << endl;
if(ans != -1) cout << 1 << " " << ans << endl << ans+1 << " " << n << endl;
}
int main() {
#ifdef xrl
freopen("in.txt", "r", stdin), freopen("out.txt", "w", stdout);
#endif
FAST_IO;
int t = 1;
cin >> t;
while(t --) solve();
#ifdef xrl
cout << "Time used = " << (double)(clock() * 1.0 / CLOCKS_PER_SEC) << "s";
#endif
return 0;
}
做題反思
去接靜態mex問題,可以使用並查集求解