Contestant. Rank 1245. Rating +30.
A. Walking Master
题意
给定两个点 \((a, b), (c, d)\),定义对于点 \((x, y)\) 的操作为下面任选一:
\(x + 1, y + 1\);
\(x - 1\)
输出从 \((a, b)\) 走到 \((c, d)\) 需要的最小操作数,无解输出 \(-1\)。
思路
画个图即可。
首先,我们需要向上移动 \(d - b\),如果 \(d - b < 0\) 就是无解。
此时,横坐标变为 \(a + d - b\),还需要向左移动 \(a + d - b - c\),如果 \(a + d - b - c < 0\) 也是无解。
若有解,输出 \(d - b + a + d - b - c\)。
时间复杂度:\(O(1)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
const int N = 2e5 + 10;
void solve(){
int a, b, c, d;
cin >> a >> b >> c >> d;
if(b > d || a + d - b < c) cout << -1 << '\n';
else cout << a + d - b - c + d - b << '\n';
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while(t --) solve();
}
就还是那么签(
B. Mex Master
题意
给定一个序列,定义答案为 由相邻数相加构成的新序列中 不在 这个序列中的 最小自然数。将序列重新排序,输出最小答案。
思路
首先,若 \(0\) 的个数小于等于 \(\frac{n + 1}{2}\),那么一定可以在连续的两个 \(0\) 里面插入一个数,使最后的序列没有 \(0\),答案即为 \(0\);
其次,若整个序列的最大值大于 \(1\),那么我们只需将 \(1\) 全部放到后面,然后第一个 \(1\) 之前不要放 \(0\) 即可,答案即为 \(1\);
接着,若整个序列的最大值为 \(1\),那么一定有一个 \(1\) 会和 \(0\) 去相加,使最后的序列出现 \(1\),而因为 \(0\) 的个数足够多,我们只需在所有 \(1\) 之间插 \(0\),就可以避免出现 \(2\),答案即为 \(2\);
否则,整个序列都是 \(0\),答案一定是 \(1\)。
时间复杂度:\(O(n)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;
void solve(){
int n;
cin >> n;
map<int, int> cnt;
int mx = 0;
for(int i=0;i<n;i++) {
int cur;
cin >> cur;
mx = max(mx, cur);
cnt[cur] ++;
}
if(cnt[0] <= (n + 1) / 2) cout << 0 << '\n';
else if(cnt[0] == n) cout << 1 << '\n';
else cout << (mx == 1 ? 2 : 1) << '\n';
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while(t --) solve();
}
一开始想错了((
C. Sequence Master
题意
若一个长为 \(2n\) 的序列,它的所有长度为 \(n\) 的子序列满足选定的数的 乘积 与剩余数的 和 相等,那么定义其为好序列。
给定一个长为 \(2n\) 的序列 \(p\),选定一个好序列,定义答案为 \(\sum|p_i - q_i|\),输出答案的最小值。
思路
猜想
首先,我们来以小见大,看看 \(a, b, c, d\) 如何成为一个好序列:
拿出其中两个式子:\(ab=c+d, ac=b+d\),我们可以得出 \(b = c\) 或 \(a = -1\)。
同理,那么我们不妨猜测整个序列都是相等的数 \(x\),或者会有至少一个数 \(t\) 不是 \(-1\)。
讨论1
下面我们来探讨一下第一个条件的局限性:
首先,它是一定成立的,毕竟 \(x=0\) 一定是一个解,但可能出现其他解;
若只有两个数,那么 \(x\) 可以为任意值;
若只有四个数,满足 \(x ^ 2 = 2x\),\(x = 2\);
若超过四个数,那么我们不难发现 \(x ^ k = kx\) 对于 \(k\) 为偶数的情况下是无整数解的。
讨论2
下面我们来探讨一下第二个条件的局限性:
我们无法让大于等于 \(2\) 个数不为 \(-1\),列式可发现无实数解;
\(n\) 为奇数的时候,依然无解;
其余情况,我们可以解得 \(t = n\)。
总结
最后,答案即为上面条件所算出的答案的最小值。
时间复杂度:\(O(2n)\)
对应AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;
void solve(){
int n;
cin >> n;
int ans = inf;
vector<int> a(2 * n);
for(int i=0;i<2*n;i++) cin >> a[i];
if(n == 1){
if(a[0] > a[1]) swap(a[0], a[1]);
ans = a[1] - a[0];
}else if(n == 2){
ans = 0;
for(int i=0;i<4;i++) ans += abs(a[i] - 2);
}
if(n % 2 == 0){
int mn = inf, sum = 0;
for(int i=0;i<2*n;i++){
sum += abs(a[i] + 1);
mn = min(mn, abs(a[i] - n) - abs(a[i] + 1));
}
ans = min(ans, sum + mn);
}
int sum = 0;
for(int i=0;i<2*n;i++) sum += abs(a[i]);
ans = min(ans, sum);
cout << ans << '\n';
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while(t --) solve();
}
漏了奇数的情况,md
有更直接的做法,这里比较麻烦