A. Broken Keyboard(简单签到)
题目链接:codeforces 1251A
题意:
键盘上有一些键坏掉了,坏掉的键按一次会出现两次,给一个按了键盘后出现的字符串,现在找出其中其中可能坏掉的键
解题思路:
只要一个字符连续出现的次数为奇数,那么这个键一定没坏,比如 aaazz,a键一定没坏,z键有可能坏了。
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
int a[30];
memset(a, 0, sizeof(a));
string s;
cin >> s;
int len = s.size();
if(len == 1){
cout << s << endl;
continue;
}
for(int i = 0; i < len; i++){
if(s[i] != s[i+1]){
a[s[i]-'a'] = 1;
}
else{
i++;
}
}
for(int i = 0; i < 26; i++){
if(a[i] == 1){
printf("%c", i+'a');
}
}
cout << endl;
}
return 0;
}
B. Binary Palindromes(思维)
题目链接:codeforces 1251B
题意:
给出n个字符串(字符串只包含0和1),字符串之间相互交换字符,字符串自身的字符也能相互交换位置(也就是每个字符可以出现在这n个字符串的任何位置),问最多能获得多少个 回文串?
解题思路:
很明显,只有n和n-1这两个答案。
而n-1的情况只有一种情况,就是所有串的长度都为偶数并且 字符0或1的个数为奇数的情况
比如 0111 1100 就只能构成1个回文串
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
string s;
int n, num0 = 0, k = 0;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> s;
int len = s.size();
for(int j = 0; j < len; j++){
if(s[j] == '0'){
num0++;
}
}
if(len % 2 == 1){
k++;
}
}
if(k == 0 && num0 % 2 == 1){
cout << n - 1 <<endl;
}
else{
cout << n << endl;
}
}
return 0;
}
C. Minimize The Integer(思维)
题目链接:codeforces 1251C
题意:
给一个数,如果两个数字相邻并且奇偶性不同,那么这两个数字可以交换位置,问交换后最小的数是多少。
解题思路:
因为偶数不能和偶数交换,那么后一个偶数必定不会交换到前一个偶数之前(无论大小),奇数同理,将奇数和偶数按顺序存起来,如果第一奇数比第一个偶数小,那么先输出第一个奇数,然后第一个偶数和第二个奇数比较,,,依次类推,输出多出来的奇数或偶数
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
string s;
cin >> s;
int len = s.size();
vector<int> even, odd;
for(int i = 0; i < len; i++){
int k = s[i] - '0';
if((k) % 2 == 0){
even.push_back(k);
}
else{
odd.push_back(k);
}
}
int i = 0, j = 0;
while(i < even.size() && j < odd.size()){
if(even[i] < odd[j]){
cout << even[i];
i++;
}
else{
cout << odd[j];
j++;
}
}
while(i < even.size()){
cout << even[i];
i++;
}
while(j < odd.size()){
cout << odd[j];
j++;
}
cout << endl;
}
return 0;
}
D. Salary Changing(二分+思维)
题目链接:codeforces 1251D
题意:
你是公司的领导,现在公司有n个人,而你手头有s元,要给这n个人发工资,发出工资总和不能超出s,每个人都有相对应的工资区间,从k 到 r(也就是这个人最少获得 k 元,最多获得 r 元),求最大 发出工资的中位数。
解题思路:
二分答案,首先将工资右区间小于 答案的划分为一类,它们必定在中位数的左侧(取它们的左区间值,使总和尽可能小),其他的则可能在右侧或者左侧,将 可能在右侧的数按工资左区间的大小排序,中位数右边的数就取 max(ans, a[i].左边界),剩下的数归为左侧
举例
5 26 (5个人,手头有26元) 4 4 (第一个人最小领4元,最多领4元) 2 3 6 8 5 6 2 7
如果此时ans = 4,那么第二个人必定在 4 的左侧,其他人则先放在右侧,右侧的人工资 发 max(他们工资的左边界, 4),右半边发完剩下的人归为左半边,他们 的工资为 他们的左边界
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
typedef long long ll;
pair<ll, ll> a[maxn];
ll n, s;
bool check(ll mid){
ll sum = 0;
vector<pair<ll, ll>> v;
for(ll i = 1; i <= n; i++){
if(a[i].second < mid){
sum += a[i].first;
}
else{
v.push_back(a[i]);
}
}
ll len = v.size();
if(len < n/2+1){
return false;
}
sort(v.begin(), v.end());
for(int i = 0; i < (n/2+1); i++){
sum += max(mid, v[len-i-1].first);
}
for(int i = 0; i < len - (n/2+1); i++){
sum += v[i].first;
}
if(sum <= s){
return true;
}
else{
return false;
}
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%lld%lld", &n, &s);
for(int i = 1; i <= n; i++){
scanf("%lld%lld", &a[i].first, &a[i].second);
}
ll l = 0, r = s;
while(l != r){
ll mid = (l + r + 1) / 2;
if(check(mid)){
l = mid;
}
else{
r = mid - 1;
}
}
printf("%lld\n", l);
}
return 0;
}