codeforces 1251A(简单签到) B(思维) C(思维) D(二分+思维)

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;
}
发布了204 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/error311/article/details/102753600