我要开始打Codeforces了,这是我的第二场比赛,本来以为可以快速上分的,谁知在pupil的路上越走越远。打算补题补到D题,在三天内完成。
本场战绩:
Cost Time: 2 hours
Solve: 1
Rank: 3989
Rating: -45
A. Broken Keyboard
题目大意:找出输入串中连续个数为奇数的字母,按字典序输出。
解法:简单模拟,对出现连续个数为奇数的字母做标记,然后遍历标记数组输出即可。
#include
using namespace std;
const int maxn = 505;
int T, n;
string s;
int mark[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) {
cin >> s;
int idx = 0, cnt = 1;
char t = s[0];
memset(mark, 0, sizeof(mark));
for (int i = 1; i < s.length(); i++) {
if (t == s[i]) {
cnt++;
} else {
if (cnt & 1) mark[t - 'a'] = 1;
t = s[i];
cnt = 1;
}
}
if (cnt & 1) mark[t - 'a'] = 1;
for (int i = 0; i < 26; i++) {
if (mark[i]) {
putchar(i + 'a');
}
}
putchar('\n');
}
return 0;
}
B. Binary Palindromes
题目大意:给定n个只包含0和1的字符串,串与串之间任意位置的字符可以相互交换,求最终可以组成多少个回文串。
解法:
由手动模拟可以知道,所有的0和1可以随意放置,于是有了下面两种解法
#include
using namespace std;
const int maxn = 505;
int T, n;
string s;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) {
cin >> n;
int len = 0, ones = 0, flag = 0;
for (int i = 0; i < n; i++) {
cin >> s;
if (s.length() & 1) flag = 1;
for (int j = 0; j < s.length(); j++)
ones += s[j] - '0';
}
if (!flag && (ones & 1)) cout << n - 1 << endl;
else cout << n << endl;
}
return 0;
}
C. Minimize The Integer
题目大意:给一个数字串,我们可以交换任意次它相邻且对应位不同为奇数或偶数的数,例如给定串"4532",4和5之间可以交换,4和3之间不能交换(不相邻),5和3不能交换(因为都是素数)。最后要使得得到的数最小。
解法:按顺序将奇数和偶数都提取出来,然后将奇数和偶数小的一方先填入,以此类推(有点像归并排序)
PS:这个方法是借鉴scnucjh大佬的。
#include
using namespace std;
const int maxn = 505;
int T;
string s;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) {
cin >> s;
vector<int> a, b, ans;
for (int i = 0; i < s.length(); i++) {
int t = s[i] - '0';
if (t & 1) a.push_back(t);
else b.push_back(t);
}
int i = 0, j = 0;
while (i < a.size() && j < b.size()) {
//将小的数先填入串中
if (a[i] < b[j]) ans.push_back(a[i++]);
else ans.push_back(b[j++]);
}
//最后将剩余的部分也填入串中
while (i < a.size()) ans.push_back(a[i++]);
while (j < b.size()) ans.push_back(b[j++]);
for (int i = 0; i < ans.size(); i++)
putchar(ans[i] + '0');
putchar('\n');
}
return 0;
}
D. Salary Changing
题目大意:给定n个员工和s块钱,每个员工要给的工资在 [ l i , r i ] [l_i,r_i] [li,ri]这个区间内,现在要使所给工资的中位数最大。
解法:最优化问题一般考虑二分法,为了保证找到的x可以成为中位数,我们先对 l i , r i l_i,r_i li,ri从大到小排序,然后二分查找中位数的值。判断条件主要考虑这个数能不能在中间位置,以及当它在中间位置是,是否够钱支付给各个员工。
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5 +10;
int T, n;
ll s;
struct People {
int a, b;
bool operator < (const People &p) {
return a^p.a ? a > p.a : b > p.b
; }
} p[maxn];
template <class T>
int read(T &res) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
res = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') res = res * 10 + (c - '0');
res *= sgn;
return 1;
}
template <class T>
void write(T x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <class T>
void writeln(T x) {
write(x);
putchar('\n');
}
int check(ll x) {
ll cnt = 0, half = (n + 1) >> 1, sum = 0;
for (int i = 1; i <= n; i++) {
if (p[i].a >= x) {
sum += p[i].a;
cnt++;
} else {
if (p[i].b >= x && cnt < half) {
sum += x;
cnt++;
} else {
sum += p[i].a;
}
}
}
if (cnt < half) return 0;
return sum <= s;
}
int main()
{
read(T);
while(T--) {
read(n); read(s);
for (int i = 1; i <= n; i++) {
read(p[i].a);
read(p[i].b);
}
sort(p + 1, p + n + 1);
ll l = 1, r = 1e18, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) l = mid + 1;
else r = mid - 1;
}
writeln(r);
}
return 0;
}
PS:参考了这篇博客:https://www.cnblogs.com/Kylin-xy/p/11735955.html