A.Greatest Convex
Link
https://codeforces.com/contest/1768/problem/A
Description
求出最大的 \(x (1 \leq x < k)\),使得 \(x! + (x - 1)!\) 是 \(k\) 的倍数。
Solution
\[x! + (x - 1)! = (x + 1) \cdot (x - 1)! \]当 \(x = k - 1\)时,\((x + 1) \cdot (x - 1)! = k \cdot (k - 2)!\),该值始终为 \(k\) 的倍数。故输出 \(k - 1\)即可。
Code
https://codeforces.com/contest/1768/submission/188069238
B.Quick Sort
Link
https://codeforces.com/contest/1768/problem/B
Description
定义一种操作:对一个长度为 \(n\) 的排列,每次可以从排列中任意选出 \(m\) 个数(将这些数从原排列中删除),将他们按升序排列后加到原排列末尾。最小化使得这个长度为 \(n\) 的排列整体升序的操作次数。
Solution
需要发现,以 \(1\) 为开头的、连续的上升序列,这些数字是不用选中的,其余的都需要选。直接计算 \(\lceil \frac {n - length} {m} \rceil\) 即可。
Code
/********************************************************
> File Name: b.cpp
> Author: zylll
> Blog: https://www.cnblogs.com/BeyondLimits/
> Created Time: 四 1/ 5 22:48:52 2023
*******************************************************/
#include <bits/stdc++.h>
const int N = 2e5 + 5;
using namespace std;
int T, n, m, a[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> T;
while (T--) {
int cnt = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
int now = 1;
for (int i = 1; i <= n; i++) {
if (a[i] == now) now++;
}
cout << (n - now + 1 + m - 1) / m << endl;
}
return 0;
}
C. Elemental Decompress
Link
https://codeforces.com/contest/1768/problem/C
Description
给定一个序列 \(a_n\),询问是否存在两个长度为 \(n\) 的排列 \(p_n,q_n\),使得 \(a_i = max(p_i, q_i), 1 \leq i \leq n\)。若存在,需输出方案。
Solution
出现以下任意一种情况都是无解的:\(a_n\)中未出现过\(n\)、\(a_n\)中\(1\)的出现次数大于\(1\)、\(a_n\)中任意一个数字的出现次数大于\(2\)。
确定有解后,先把那些一定要填的数字填好,剩余数字结合贪心思路,每次能往大里填(结合\(lower\)_\(bound\)即可)。
Code
/********************************************************
> File Name: c.cpp
> Author: zylll
> Blog: https://www.cnblogs.com/BeyondLimits/
> Created Time: 四 1/ 5 23:00:22 2023
*******************************************************/
#include <bits/stdc++.h>
const int N = 2e5 + 5;
using namespace std;
int T, n, cnt[N], a[N], ans1[N], ans2[N];
bool vis1[N], vis2[N];
vector<int> fi, se;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> T;
while (T--) {
bool flag = false;
cin >> n;
for (int i = 1; i <= n; i++) cnt[i] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]]++;
if (cnt[a[i]] > 2) flag = true;
}
flag |= (cnt[1] == 2);
flag |= (!cnt[n]);
if (flag) cout << "NO" << endl;
else {
fi.clear();
se.clear();
for (int i = 1; i <= n; i++) {
vis1[i] = vis2[i] = false;
ans1[i] = ans2[i] = 0;
}
for (int i = 1; i <= n; i++) {
if (!vis1[a[i]]) {
vis1[a[i]] = true;
ans1[i] = a[i];
}
else {
ans2[i] = a[i];
vis2[a[i]] = true;
}
if (a[i] == 1) {
vis1[1] = vis2[1] = true;
ans1[i] = ans2[i] = 1;
}
}
for (int i = n; i >= 1; i--) {
if (!vis1[i]) se.push_back(i);
if (!vis2[i]) fi.push_back(i);
}
for (int i = 1; i <= n; i++) {
if (!ans1[i]) {
auto it = lower_bound(se.begin(), se.end(), ans2[i], greater<int>());
if (it == se.end()) {
flag = true;
break;
}
ans1[i] = se[it - se.begin()];
se.erase(it);
}
}
for (int i = 1; i <= n; i++) {
if (!ans2[i]) {
auto it = lower_bound(fi.begin(), fi.end(), ans1[i], greater<int>());
if (it == fi.end()) {
flag = true;
break;
}
ans2[i] = fi[it - fi.begin()];
fi.erase(it);
}
}
if (flag) cout << "NO" << endl;
else {
cout << "YES" << endl;
for (int i = 1; i <= n; i++) {
cout << ans1[i];
i == n ? cout << endl : cout << " ";
}
for (int i = 1; i <= n; i++) {
cout << ans2[i];
i == n ? cout << endl : cout << " ";
}
}
}
}
return 0;
}
D.Lucky Permutation
Link
https://codeforces.com/contest/1768/problem/D
Description
定义一种操作:对一个长度为 \(n\) 的排列 \(a_n\),每次可以从排列中选出 \(i\) 和 \(j\) ,交换 \(a_i\) 与 \(a_j\)。最小化使得最终的 \(a_n\) 有且仅有一个逆序对的操作次数。
Solution
对于每个 \(i\),若考虑从 \(a_i\) 到 \(i\) 连一条有向边,根据排列的性质(每个点的入度和出度都为 \(1\)),则会生成 \(x\) 个环 \((1 \leq x \leq n)\)。
不难发现,最终状态一定是「一个升序排列,且选择一对相邻的数交换后」的形式。若按之前的图的形式表示,则可以表示为 \(n - 1\) 个自环 + \(1\) 个长度为 \(2\) 的环(且这个长度为 \(2\) 的环,是由两个相邻的数字构成的)。
对于原排列表示出的 \(x\) 个环,自环可以不管,大环则需要被拆解成小环和自环。当交换两个数有效时,可以等效为「大环变小,且新增自环」。若存在一个大环其中包含两个相邻的数,那么意味着在拆解的过程中,可以把他们俩留下,其他变为自环。否则在所有大环拆成自环后,还需要选择两个相邻的自环,将他们变成长度为 \(2\) 的环。
利用并查集可以找出环的个数后,再在每个环中判断,是否存在相邻元素。若存在则答案 \(-1\),不存在则答案 \(+1\)。
Code
/********************************************************
> File Name: d.cpp
> Author: zylll
> Blog: https://www.cnblogs.com/BeyondLimits/
> Created Time: 五 1/ 6 23:17:07 2023
*******************************************************/
#include <bits/stdc++.h>
const int N = 2e5 + 5;
using namespace std;
int T, n, x, fa[N];
set<int> s, son[N];
int get_fa(int x) { return x == fa[x] ? x : fa[x] = get_fa(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
freopen("in","r", stdin);
cin >> T;
while (T--) {
bool flag = false;
cin >> n;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= n; i++) {
cin >> x;
int fx = get_fa(i), fy = get_fa(x);
fa[fy] = fx;
}
for (int i = 1; i <= n; i++) {
int x = fa[i];
while (x != fa[x]) x = fa[x];
s.insert(x);
son[x].insert(i);
}
for (int i = 1; i <= n; i++) {
int last = -1;
for (auto x : son[i]) {
if (last != -1 && x - last == 1) {
flag = true;
break;
}
last = x;
}
if (flag) break;
}
cout << n - (int)s.size() + (!flag ? 1 : -1) << endl;
s.clear();
for (int i = 1; i <= n; i++) son[i].clear();
}
return 0;
}
标签:842,int,flag,cin,fa,2023.1,https,Div,com
From: https://www.cnblogs.com/BeyondLimits/p/17032035.html