链接:
Codeforces Round 987 (Div. 2)
A:Penchick and Modern Monument
大意:
单调非增序列操作多少步变成单调非减
思路:
最后的数一定是相同的,为出现次数最多的那个数,结果就是n减去出现次数最多的数
代码:
#include <bits/stdc++.h>using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =void solve()
{int n;cin >> n;vi a(n + 1);for (int i = 1; i <= n; i++)cin >> a[i];int mx = 0;for (int i = 1; i <= n; i++){int j = i;while (i <= n && a[i] == a[j])i++;mx = max(i - j, mx);i--;}cout << n - mx << endl;
}signed main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) solve();return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
B:Penchick and Satay Sticks
大意:
一个排列转换成123456...n的最小字典序排列,每次转换只能相邻1个并且数值不能相差超过1,求是否能转换
思路:
相差不能超过1,则只能与位置相邻的数进行交换,即如果i不在位置i上,必然就在位置i-1或者i + 1上,如果都没有,就不能转换
那么可以从左到右遍历,如果 i !=a[i] 并且跟后边差1,就跟右边交换即可,换完还不等,就不能转换
代码:
#include <bits/stdc++.h>using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =void solve()
{int n;cin >> n;vi a(n + 1);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] == i && abs(a[i + 1] - a[i])==1)swap(a[i], a[i + 1]);else{cout << "NO" << endl;return;}}}cout << "YES" << endl;
}signed main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1; cin >> t;while (t--) solve();return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
C:Penchick and BBQ Buns
大意:
给一个长度n的每个点上都赋一个值,如果赋了相同的值,任意两个相同的值之间要满足距离之差等于某个整数的平方和,求赋值方案,没有则输出-1
思路:
先对n进行奇偶分析,如果偶数的话就好了,直接两两相邻,距离差为1
奇数的话可以转换成偶数的情况,我们需要一个三个点的那就是距离为9和距离为16的,最小的情况下给1,10,26同种,发现1-10之间可以填偶数个,直接填就行,10到26之间填奇数个,可以多一个距离差为4的一个在10-26之内,一个在之外,这样距离差为4的里面再塞一对,前面的几对也塞一下就行了,所以27是最小的奇数合法情况
代码:
#include <bits/stdc++.h>using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =void solve()
{int n;cin >> n;if (n & 1){if (n < 27)cout << -1 << endl;else{vi ans(n + 1);int cnt = 2;int num = 0;for (int i = 1; i <= n; i++){if (i == 1 || i == 10 || i == 26)ans[i] = 1e6;else if (i == 23 || i == 27)ans[i] = 1e6-1;else{ans[i] = cnt;num++;if (num == 2){num = 0;cnt++;}}}for (int i = 1; i <= n; i++)cout << ans[i] << ' ';}}else{int num = n / 2;for (int i = 1; i <= num; i++)cout << i << " " << i << " ";cout << endl;}}signed main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) solve();return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
D:Penchick and Desert Rabbit
大意:
一个数组,位于i的数可以跳到右边比他小的数,可以跳到左边比他大的数,求从每一位开始最后可以跳到的最大数
思路:
有一个性质就是,一个数如果能跳到另一个数上,那么这两个位置的答案会一样
首先要想的是要跳到最大,应该是先往右跳,跳到最靠右的,然后往左跳才会有最大的,但是从左到右找最靠右的不太好找,pass
从右往左找的话,可以知道最靠右的就是自己,然后这个的答案就是前n个取最大,并且可知右边的能跳的肯定大于等于左边的能跳到的数,对于位置i,直接取i后面数的最小值,看看i是否大于后面最小值,如果大于,那么,那么i肯定直接或间接能到i + 1,那么i的答案跟i + 1的答案是相同的;如果小于等于,那么i到不了右边任何一个,只能取前面的最大值。
所以求一下前缀最大值和后缀最小值依次从右往左即可。
代码:
#include <bits/stdc++.h>using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =void solve()
{int n;cin >> n;vi a(n + 1);for (int i = 1; i <= n; i++)cin >> a[i];vi ans(n + 1), p(n + 1), s(n + 1);p[1] = a[1], s[n] = a[n];for (int i = 2; i <= n; i++)p[i] = max(p[i - 1], a[i]);for (int i = n - 1; i > 0; i--)s[i] = min(a[i], s[i + 1]);ans[n] = p[n];for (int i = n - 1; i; i--){if (p[i] > s[i + 1])ans[i] = ans[i + 1];else ans[i] = p[i];}for (int i = 1; i <= n; i++)cout << ans[i] << ' ';cout << endl;
}signed main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t = 1;cin >> t;while (t--) solve();return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/