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;
}