Codeforces Round #624 (Div. 3)
【A.Add Odd or Subtract Even】
【题目大意】
给你两个正整数a和b,每次你可以选择将a加上一个奇数或者将a减去一个偶数,问你操作多少次后可以将a变成b
【解题思路】
如果a = b显然答案为0
如果a < b:
如果(b - a) % 2 == 0,那么我们可以将a加至b + 1然后再减去1,答案为2
否则直接让a加到b,答案为1
如果a > b:
如果(a - b) % 2 == 0,那么我们直接让a减至b,答案为1
否则我们将a减至b - 2然后再加上2,答案为2
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int a, b;
cin >> a >> b;
int ans = 0;
if (a < b) {
if ((b - a) & 1) ans = 1;
else ans = 2;
}
else if(a > b){
if ((a - b) & 1) ans = 2;
else ans = 1;
}
cout << ans << endl;
}
return 0;
}
【B.WeirdSort】
【题目大意】
给你数组a和数组p,你可以将a[p[i]]与a[p[i] + 1]交换,问你经过有限次交换使得数组a非降序排列
【解题思路】
考虑交换排序的思想,如果ai > aj那么我们看p数组中i - j是否均存在
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int a[110];
bool p[110];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
memset(p, false, sizeof(p));
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= m; ++i) {
int x;
cin >> x;
p[x] = true;
}
bool flag = false;
for (int i = 1; i < n; ++i) {
for (int j = i + 1; j <= n; ++j) {
if (a[i] > a[j]) {
int index = i;
while (index < j && p[index]) ++index;
if (index < j) {
flag = true;
break;
}
swap(a[i], a[j]);
}
}
if (flag) break;
}
if (flag) cout << "NO" << endl;
else cout << "YES" << endl;
}
return 0;
}
【C.Perform the Combo】
【题目大意】
有一个长度为n的字符串s和一个数组p,你每次打字打到s[pi]时就会从头开始,问你’a’ - 'z’的所有字符被打印的次数是多少
注意最后s还要被完整打印一次
【解题思路】
有一个暴力的O(nm)的做法就是遍历s和p每次将num[s[i]]++,但是显然超时,考虑优化算法,我们可以将s中的字符的位置记录到vector(v[26])中,然后遍历p,如果v[‘a’ - ‘z’]中有字符的位置小于p[i],我们找到其最后一个大于p[i]的位置,复杂度O(m * 26 * lgn)
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 2e5 + 10;
int num[26];
int p[maxn];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, m;
string s;
cin >> n >> m >> s;
memset(num, 0, sizeof(num));
for (int i = 1; i <= m; ++i) cin >> p[i];
vector<int> v[26];
for (int i = 0; i < n; ++i) {
v[s[i] - 'a'].push_back(i + 1);
++num[s[i] - 'a'];
}
for (int i = 1; i <= m; ++i) {
for (int j = 0; j < 26; ++j) {
if (!v[j].size()) continue;
int index = upper_bound(v[j].begin(), v[j].end(), p[i]) - v[j].begin();
num[j] += index;
}
}
for (int i = 0; i < 26; ++i) cout << num[i] << " ";
cout << endl;
}
return 0;
}
【D.Three Integers】
【题目大意】
给你三个正整数a,b,c (a <= b <= c),每次你可以将其中一个数加上或减去1,问你最少操作多少次可以使得a整除b且b整除c
【解题思路】
推了半个多小时公式结果最后打了个暴力,没想到正解就是暴力,大概意思就是枚举a和b,首先ansa的范围一定在1到2c之间,然后ansb一定是ansa的倍数,最后考虑将c变成c - c % ansb或者c + ansb - c % ansb,找到所有组合中sum最小的即可
【AC代码】
//当时为了防止超时加了register常数优化
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
register int T;
cin >> T;
while (T--) {
int a, b, c;
cin >> a >> b >> c;
register int ansa = a, ansb = b, ansc = c;
register int sum = 0x3f3f3f3f;
register int cc = c << 1;
for (register int i = 1; i <= cc; ++i) {
for (register int j = i; j <= cc; j += i) {
int k = 0;
if (c % j < j - c % j) k = c - c % j;
else k = c + j - c % j;
if (sum > abs(i - a) + abs(j - b) + abs(k - c)) {
sum = abs(i - a) + abs(j - b) + abs(k - c);
ansa = i, ansb = j, ansc = k;
}
}
}
cout << sum << endl;
cout << ansa << " " << ansb << " " << ansc << endl;
}
return 0;
}