Codeforces Round #792 (Div. 1 + Div. 2) A - E 题解
A. Digit Minimization
一开始以为是只能换相邻的,wa 了好多发
如果是 n = 2 的话,只能是第二个
其他的情况就都是最小的那个,把最小的放到第一个,然后剩下的慢慢磨
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int num[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
string s;
cin >> s;
int n = s.length();
int ans = 0;
if(n == 1) ans = s[0] - '0';
else if(n == 2) ans = s[1] - '0';
else
{
ans = 10;
for(int i=0; i<n; i++) ans = min(ans, s[i] - '0');
}
cout << ans << endl;
}
return 0;
}
B. Z mod X = C
一个构造题
因为给了约束条件: \(1 \leq a < b < c \leq 10^8\)
我们按照条件构造一下就行了
$z = c, y = b, x = b * c + a $
构造方式还挺多,随便构造就行
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
ll a, b, c;
cin >> a >> b >> c;
ll y = b, z = c;
ll x = b * c + a;
cout << x << " " << y << " " << z << endl;
}
return 0;
}
C. Column Swapping
这个题目的 pretest 真的太弱了吧
首先要明确的是,如果成立的话,最终排序后的数组的样子是唯一的
然后我们就找对于每一行有多少列是不匹配的,然后换就行,如果有 3 个及以上,显然不成立
找到要换的两列后,直接交换这两列,判断是否成立就行
我被 hack 是引入了原本的 index 作为判断,显然有点多余,还会错
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 10;
vector<int>gra[maxn], a[maxn], nex[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n, m;
cin >> n >> m;
int f = 1;
for(int i=0; i<n; i++)
{
nex[i].clear();
a[i].clear();
gra[i].clear();
for(int j=0; j<m; j++)
{
int x;
cin >> x;
gra[i].push_back(x);
a[i].push_back(x);
}
sort(a[i].begin(), a[i].end());
for(int j=0; j<m; j++)
{
if(a[i][j] != gra[i][j])
nex[i].push_back(j);
}
if(nex[i].size() >= 3) f = 0;
}
if(f == 0) {cout << -1 << endl; continue;}
int l = -1, r = -1;
for(int i=0; i<n && l == -1; i++)
{
if(nex[i].size() == 2)
{
l = nex[i][0];
r = nex[i][1];
}
}
if(l == -1) l = r = 0;
for(int i=0; i<n; i++)
{
swap(gra[i][l], gra[i][r]);
for(int j=1; j<m; j++)
{
if(gra[i][j] < gra[i][j-1])
f = 0;
}
}
if(f == 0) cout << -1 << endl;
else cout << l + 1 << " " << r + 1 << endl;
}
return 0;
}
D. Traps
贪心
第一个要明确的是,我们一定要取完 k 个。如果有一个解是没取完 k 个的,必然有一个更优解:取走最后一个没有被取走的陷阱
假设我们只取一个,那么对于第 \(i\) 个位置的陷阱,我们跳过这个陷阱,减少的伤害值应该是 \(a_i - (n - i)\),\(a_i\) 是本身陷阱的值,\(n - i\) 是他给后面的陷阱提供的额外值
如果我们取 \(k\) 个,那么额外值就不一定是 \(n - i\) 了,但是这并不会对我们之前的贪心造成影响。
跳到整个局面来看,我们取 k 个,对于第一个拿走的陷阱,他造成的额外值,必然会减少 \(k - 1\),因为后面有 \(k - 1\) 个陷阱要拿走,同理对于第二个也是 \(k - 2\)
所以这个额外值的减少对于整个局面来说是个定值:
因此最终只需要按照 \(a_i - (n - i)\) 进行贪心,选择最大的 k 个即可
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int num[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
ll n, m;
cin >> n >> m;
ll sum = 0;
for(int i=1; i<=n; i++)
{
cin >> num[i];
sum += num[i];
num[i] = num[i] - (n - i);
}
sort(num + 1, num + 1 + n);
for(int i=0; i<m; i++)
sum -= num[n - i];
sum -= m * (m - 1) / 2;
cout << sum << endl;
}
return 0;
}
E. MEX vs DIFF
贪心
先把 MEX 的最大值计算出来,然后贪心的找比 MEX 大的数,改变他们的值去填补 MEX
贪心的地方在于:我们已知 MEX 一定能够补充到一开始计算的最大值,因此我们选择哪些数是一个问题
如果我们选择的数只出现了单个,那么 DIFF 没变
如果我们选择的数出现了若干次,那么 DIFF + 1
因此我们要贪心出现次数少的
如果是一边推 MEX,一边选取最大值的情况,不能保证贪心是最优秀的,因为没有考虑上述的情况
给一个例子:
10 2
2 3 4 5 6 8 10 10 10 10
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
ll num[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n, m;
cin >> n >> m;
for(int i=0; i<n; i++)
cin >> num[i];
sort(num, num + n);
int tp = 0, now = 0;
for(int i=0; i<n && now <= m; i++)
{
while(tp < n && num[tp] < i) tp++;
if(num[tp] != i) now++;
else tp++;
}
map<int, int>cnt;
for(int i=tp; i<n; i++)
cnt[num[i]]++;
priority_queue<int>q;
for(auto it=cnt.begin(); it!=cnt.end(); it++)
q.push(-it->second);
while(q.size() && m)
{
int now = -q.top();
if(m >= now) q.pop();
m -= min(m, now);
}
cout << q.size() << endl;
}
return 0;
}