P10131 [USACO24JAN] Majority Opinion B 题解
大意:
给定你一个长度为 \(n\) 的序列 \(\{h\}\),\(1\le h_i\le n\),你可以对其进行若干次操作,操作为:
- 选定一个区间 \([l,r]\)。
- 若在 \(i\in[l,r]\) 中存在 \(h_i\) 的数量大于 \(\lfloor\frac{l+r}{2}\rfloor\),则令所有的 \(k\in[l,r]\) 上的 \(h_k=h_i\)
求所有可能使 \(\{h\}\) 中的所有元素都变成 \(h_i\) 的 \(h_i\) 个数,并以升序输出可能的 \(h_i\),或判断无解。
分析:
先给出结论,如果存在一个长度为 3 的区间有 2 个及以上的 \(h_i\),那么 \(h_i\) 就是合法的。
考虑证明。
先证明充分性,对于一个长度为 3 的区间,若存在两个及以上的相同元素,则这个区间可以变为相同元素,而我们将该区间变为相同元素后,可以一个一个地扩展左右边界,因为区间长度只加一,而除了新加进来的这个元素,其他元素都是相同的,所以这个元素也会变成相同的,这样就可以保证扩展到整个区间。证毕。
再证明必要性,区间长度小于 3 时是显然的,区间长度大于 3 时,所需要的最少相同元素个数就是 \(\lfloor\frac{l+r}{2}\rfloor+1\),\(r-l+1\) 为奇数时,想要在该区间内获得最长的相同元素个数小于 \(\lfloor\frac{l_1+r_1}{2}\rfloor+1\) 的区间 \([l_1,r_1]\) 就需要隔一个放一个 \(h_i\),但即使如此也才能得到 2,无论向左或向右扩展都是得到一个长度为 3 的区间且相同元素个数大于半区间长。\(r-l+1\) 为偶时也是要隔开放置,然后在此基础上还要在其中隔开来的地方再放一个 \(h_i\),显然得不到长度为 3 及以上。由上可知,所有的区间长度大于 3 的合法区间里面都含有区间长度为 3 的小合法区间。证毕。
Code:
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define ll long long
#define ull unsigned long long
#define m_p make_pair
#define m_t make_tuple
using namespace std;
using namespace __gnu_pbds;
int h[200010];
bitset<200010> v;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T, n, x, fl;
cin >> T;
while (T--)
{
cin >> n;
fl = 0;
for (int i = 1; i <= n; i++)
{
cin >> x;
if (h[x] && (h[x] == i - 1 || h[x] == i - 2))
v[x] = 1;
h[x] = i;
}
for (int i = 1; i <= n; i++)
{
if (v[i])
{
if(fl)
cout << " ";
cout << i;
fl = 1;
}
v[i] = 0;
h[i] = 0;
}
if(!fl)
cout << "-1";
cout << "\n";
}
return 0;
}