A. Penchick and Modern Monument
思路
保留原来 nnn 个数中数量最多的一种数字,然后修改其他数使得序列不递减。
复杂度
时间复杂度 O(n)O(n)O(n),空间复杂度 O(n)O(n)O(n)
代码实现
// Problem: A. Penchick and Modern Monument
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e4 + 5, M = 17;
int n;
int a[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int ma = 0;
for (int i = 1; i <= n; i++) {
int j = i;
while (j <= n && a[i] == a[j]) {
j++;
}
ma = max(ma, j - i);
i = j - 1;
}
int ans = n - ma;
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
B. Penchick and Satay Sticks
思路
赛时思路:
发现形如 3,2,13,2,13,2,1 这样子安排,111 是无法移动到第一个位置的,那么 111 开始时要么在第一个位置,要么在第二个位置,然后 222 在第一个位置。
当把 111 放到第一个位置的时候,222 就变成了剩下 n−1n-1n−1 个数的第一个数,也是进行相同的判断。
因此,可以从左到右遍历,如果 pi=ip_i = ipi=i,那么当前最小的数就安排好了位置,否则 pi≠ip_i \ne ipi=i,如果 pi+1≠ip_{i+1} \ne ipi+1=i 无解,否则交换 pi,pi+1p_i,p_{i+1}pi,pi+1,然后接着判断 pi+1p_{i+1}pi+1,直到判断完所有数为止。
题解思路:
如果数字 iii 初始位置与 最后的位置 iii 的距离超过 111,那么就无法把数字 iii 移动到最后的位置。
因此,若 ∣pi−i∣|p_i - i|∣pi−i∣ 的最大值是大于 111 的,那么无解,否则有解。
复杂度
时间复杂度 O(n)O(n)O(n),空间复杂度 O(n)O(n)O(n)
代码实现
// Problem: B. Penchick and Satay Sticks
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/B
// Memory Limit: 256 MB
// Time Limit: 1500 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 17;
int n;
int a[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
if (a[i] != i) {
if (i + 1 <= n && a[i + 1] == a[i] - 1) {
swap(a[i], a[i + 1]);
}
}
if (a[i] != i) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
C. Penchick and BBQ Buns
思路
如果 nnn 为偶数,那么可以相邻的两个数两两作为一组,距离为 111 恰好是一个平方数。
如果 nnn 为奇数,手玩发现有解的最小奇数为 272727。
因为不超过 272727 的范围内有平方数 9+16=259+16=259+16=25,若答案序列为 aaa,可以令 a1,a10,a26a_1,a_{10},a_{26}a1,a10,a26 作为一组,a11,a27a_{11},a_{27}a11,a27 作为一组,然后剩下的数与相邻的数从左到右两两作为一组。
复杂度
时间复杂度 O(n)O(n)O(n),空间复杂度 O(n)O(n)O(n)
代码实现
// Problem: C. Penchick and BBQ Buns
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e4 + 5, M = 17;
void solve()
{
int n;
cin >> n;
if (n % 2 == 0) {
int p = 1;
for (int i = 1; i <= n; i += 2) {
cout << p << ' ' << p << ' ';
p++;
}
cout << '\n';
} else {
if (n < 27) {
cout << "-1\n";
return;
}
int p = 1;
vector<int> a(n + 1);
a[1] = a[10] = a[26] = p++;
for (int i = 2; i < 10; i += 2) {
a[i] = a[i + 1] = p++;
}
a[11] = a[27] = p++;
for (int i = 12; i < 26; i += 2) {
a[i] = a[i + 1] = p++;
}
for (int i = 28; i <= n; i += 2) {
a[i] = a[i + 1] = p++;
}
for (int i = 1; i <= n; i++) {
cout << a[i] << ' ';
}
cout << '\n';
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
D. Penchick and Desert Rabbit
思路
如果区间 [l,r][l,r][l,r] 中的最大高度为 ala_lal,那么 [l,r][l,r][l,r] 中的任意一个位置出发,可以向左跳到 lll 位置,取得高度 ala_lal。
如果区间 [l1,r1][l_1,r_1][l1,r1] 满足 l1>rl_1>rl1>r,al1a_{l_1}al1 为 [l1,r1][l_1,r_1][l1,r1] 的最大值,且 al1>ala_{l_1}>a_lal1>al,[l1,r1][l_1,r_1][l1,r1] 的最小值小于 ala_lal,那么从 [l,r][l,r][l,r] 中的任意位置出发,可以向左跳到 lll 位置,然后再跳到 [l1,r1][l_1,r_1][l1,r1] 的最小值位置,在跳到 l1l_1l1 位置,取得更大的高度 al1a_{l_1}al1。
通过上面的思考,可以发现,如果 aia_iai 为 [1,n][1,n][1,n] 中的下标最小的最大值。(就是说如果存在多个最大值,iii 是最大值下标中的最小下标。),那么从 [i,n][i,n][i,n] 中的任意位置出发,都可以跳到最大高度 aia_iai。
如果 [1,i−1][1,i-1][1,i−1] 中的下标最小的最大值为 aja_jaj,那么从 [j,i−1][j,i-1][j,i−1] 中的任意位置出发,可以跳到高度 aja_jaj。
如果要跳到高度 aia_iai,那么需要 [i,n][i,n][i,n] 中存在一个高度 ak<aja_k < a_jak<aj,也就是说 [i,n][i,n][i,n] 中的最小高度要小于 aja_jaj,才能使得从 [j,i−1][j,i-1][j,i−1] 中的任意位置出发,能够跳到高度 aia_iai,否则能跳到的最大高度就是 aja_jaj。
继续向左找下标最小的最大值,这样子会划分出若干个连续的子区间,满足上一个子区间的右端点加一为下一个子区间的左端点,子区间的左端点的值为整个子区间的最大值,且子区间的最大值是从右到左递减的。
(要快速找下标最小的最大值,可以先预处理出 ststst 表,然后用 ststst 表进行查询,下面找区间内的最小值同样也是可以用 ststst 表。)
对于在同一个子区间内的位置,最终都能达到的高度都是相同的。
对于一个子区间 [l,r][l,r][l,r],如果右边存在一个子区间 [l1,r1][l_1,r_1][l1,r1]的最小高度小于子区间 [l,r][l,r][l,r] 的最大高度,那么子区间 [l,r][l,r][l,r] 内的位置可以达到的最大高度就可以为子区间 [l1,r1][l_1,r_1][l1,r1] 能达到的最大高度。
可能右边会存在多个子区间的最小高度,小于子区间 [l,r][l,r][l,r] 的最大高度,这些子区间中的最大高度的最大值,就是区间 [l,r][l,r][l,r] 内的位置可以达到的最大高度。
直接遍历右边子区间,看哪些子区间的最小高度大于区间 [l,r][l,r][l,r] 的最大高度,显然是会超时的。
可以用权值线段树进行维护,维护的单点 xxx 的数值,表示右边子区间的最小高度为 xxx 的能达到的最大高度。
当遍历到一个子区间 [l,r][l,r][l,r] 时,就可以查询最小高度在 [1,al−1][1,a_l-1][1,al−1] 范围内的,右边的子区间能达到的最大高度,与 ala_lal 比较取最大值,即是 [l,r][l,r][l,r] 能达到的最大高度。
遍历完子区间 [l,r][l,r][l,r] 后,就可以新该子区间最小高度的对应数值,然后求解区间 [1,l−1][1,l-1][1,l−1]。
复杂度
时间复杂度 O(nlogn)O(n\log n)O(nlogn),空间复杂度 O(nlogn)O(n \log n)O(nlogn)
代码实现
// Problem: D. Penchick and Desert Rabbit
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/D
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 5, M = 20;
int n;
int f[N][M], g[N][M];
int a[N], ans[N];
int query_st(int l, int r, int op)
{
int k = log2(r - l + 1);
if (!op) {
int id1 = f[l][k];
int id2 = f[r - (1 << k) + 1][k];
return a[id2] > a[id1] ? id2 : id1;
} else {
int id1 = g[l][k];
int id2 = g[r - (1 << k) + 1][k];
return a[id2] < a[id1] ? id2 : id1;
}
}
struct {
int l, r, v;
} tr[4 * N];
void build(int u, int l, int r)
{
tr[u].l = l, tr[u].r = r, tr[u].v = 0;
if (l != r) {
int mid = (l + r) >> 1;
build(u * 2, l, mid);
build(u * 2 + 1, mid + 1, r);
}
}
void pushup(int u)
{
tr[u].v = max(tr[u * 2].v, tr[u * 2 + 1].v);
}
void modify(int u, int p, int x)
{
if (tr[u].l == tr[u].r) {
tr[u].v = max(tr[u].v, x);
return;
}
int mid = (tr[u].l + tr[u].r) >> 1;
if (p <= mid)
modify(u * 2, p, x);
else
modify(u * 2 + 1, p, x);
pushup(u);
}
int query(int u, int l, int r)
{
if (l <= tr[u].l && tr[u].r <= r)
return tr[u].v;
int res = 0;
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid)
res = max(res, query(u * 2, l, r));
if (r > mid)
res = max(res, query(u * 2 + 1, l, r));
return res;
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
ans[i] = 0;
}
for (int j = 0; j < M; j++) {
int step = 1 << (j - 1);
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
if (!j) {
f[i][j] = g[i][j] = i;
} else {
f[i][j] = f[i][j - 1];
if (a[f[i + step][j - 1]] > a[f[i][j]]) {
f[i][j] = f[i + step][j - 1];
}
g[i][j] = g[i][j - 1];
if (a[g[i + step][j - 1]] < a[g[i][j]]) {
g[i][j] = g[i + step][j - 1];
}
}
}
}
build(1, 1, n);
int r = n;
while (r >= 1) {
int l = query_st(1, r, 0);
int v = a[l];
if (a[l] > 1) {
v = max(query(1, 1, a[l] - 1), v);
}
for (int i = l; i <= r; i++) {
ans[i] = v;
}
int w = a[query_st(l, r, 1)];
modify(1, w, v);
r = l - 1;
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << ' ';
}
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
1809

被折叠的 条评论
为什么被折叠?



