暑假训练第一周第五天

题意:
A(CodeForces - 1251E1&E2):有n个人,每个人有各自的mi 和 pi。 如果有mi个人投你,那么他也会投你,如果不是mi个人投你,若让他投你,你就得花费pi 去贿赂他,问所有人投你要花费多少。
B(CodeForces - 1251C):一个数字字符串,如果相邻的两个数奇偶性不同则可以交换,问你这个数字最后最小是多少,保留零。
C(CodeForces - 1251A):键盘坏了,按某个键会自动多按一次,找一定好的键。
D(CodeForces - 1251D):N个员工,一共有K元钱,每个员工工资有范围,问怎么分配才能让工资中位数最大。
E(CodeForces - 1251F):给你一堆木条,一些是白色的,一些是红色的。然后要把这些木条拼到一起构成长度先递增后递减的样子,然后要求红色木条长度最长,问最后使得这个拼凑出来的多边形的周长为Qi的方案数是多少。
F(CodeForces - 1251B):n串01字符串,问你经过任意交换后,最后能得到多少个回文串。

补题:
A codeforces1251E1 Voting
思路:向后枚举,从n到1进行选择。如果当前人数有i个的话,就可以全投了,pi的处理其实就好的多了,我们可以用贪心的办法解决,如果说 N - size < i,那么,我们的size一定是偏大了,我们就可以去把偏大的部分给买通了,这时候就可以用优先队列去找这size里面的最小p值即可。
代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
const int maxN = 2e5 + 7;
int N;
vector<int> vt[maxn];
using namespace std;
int main()
{
    int T,m,p; 
	cin>>T;
    while(T--)
    {
        scanf("%d", &N);
        for(int i=0; i<=N; i++) vt[i].clear();
        for(int i=1; i<=N; i++) { scanf("%d%d", &m, &p); vt[m].push_back(p); }
        priority_queue<int, vector<int>, greater<int>> Q;
        ll ans = 0;
        for(int i=N; i>=0; i--)
        {
            int len = (int)vt[i].size();
            for(int j=0; j<len; j++) Q.push(vt[i][j]);
            while(Q.size() > N - i) { ans += Q.top(); Q.pop(); }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

B CodeForces - 1251C Minimize The Integer
思路:数组分成奇数和偶数两组,两组相对位置不变。每次输出两个数组中的小数。
代码:

#include<bits/stdc++.h>
using namespace std;
int t,l;
char x[300010],y[300010];
string a;
int main()//相对位置不变
{
cin>>t;
while(t--){
    cin>>a;
    l=a.size();
    int i=0, j=0,l1=0,l2=0;
    for(i=0;i<l;i++){
        if((a[i]-'0')%2==1)
            x[l1++]=a[i];
            else
            y[l2++]=a[i];
    }
    i=0;
    j=0;
    while(i < l1 || j < l2)
        {
            if(i >= l1)
                cout<<y[j++];
            else if(j >= l2)
                cout<<x[i++];
            else if(x[i] <= y[j])
                cout<<x[i++];
            else
                cout<<y[j++];
        }
    cout<<endl;
}
}

C CodeForces - 1251A Broken Keyboard
思路:出现重复的数直接跳过,单个出现的数,统计数组自加。
代码:

#include<bits/stdc++.h>
using namespace std;
int t,l;
string s;
int main()
{
cin>>t;
while(t--){
    cin>>s;
    l=s.size();
    int a[27]={0};
    for(int i=0;i<l;i++){
            if(s[i]==s[i+1])
            i++;
        else
            a[s[i]-'a'+1]++;
    }
    for(int i=1;i<27;i++)
        if(a[i]>0)
        cout<<char(i+'a'-1);
    cout<<endl;
}
}

D CodeForces - 1251D Salary Changing
思路:用pair数组存储每个员工的最小和最大工资,然后进行降序排序。记过程中工资中位数为mid,我们选定一个区间二分查找这个mid;如果所有员工都发放最小工资,那么此刻的mid就应该是所有mid的下界,而总工资S则应该是mid的上界。每次选定一个mid后,我们应该判断这个mid合不合适,判断条件是能找到(n+1)/2个人的工资可以达到mid且总工资不会超过S,排序+贪心选取这个(n+1)/2个人。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> P;
#define fi first
#define sc second
#define rp(i,n) for(int i=0;i<n;i++)
#define rpn(i,n) for(int i=1;i<=n;i++)
const int MAX_N=2e5+5;
P emp[MAX_N];
int n,num;
LL s;
bool ok(LL mid){
	LL cost=0;
	int ans=0;
	rp(i,n){
		if(emp[i].fi>=mid) ans++;
		else if(emp[i].sc>=mid){
			cost+=mid-emp[i].fi;
			ans++;
		}
		if(cost>s) return false;
		if(ans==num) return true;
	}
	return false;
}
int main(){
	IOS;
	int t;
	cin>>t;
	while(t--){		
		cin>>n>>s;
		num=(n+1)>>1;
		rp(i,n) cin>>emp[i].fi>>emp[i].sc;
		sort(emp,emp+n,greater<P>());
		LL lf=emp[n>>1].fi,rt=s,rs;
		rp(i,n) s-=emp[i].fi;
		while(rt>=lf){
			LL mid=(lf+rt)>>1;
			if(ok(mid)){
				lf=mid+1;
				rs=mid;
			}
			else rt=mid-1;
		}
		cout<<rs<<'\n';
	}
	return 0;
}

F CodeForces - 1251B Binary Palindromes(贪心)
思路:首先奇数不用管,已有的奇数也全部变成偶数。统计0和1的数目,每次只要放偶数个0和偶数个1就一定行。将0和1都变成偶数(奇数减1)之后,实际上二者等价,合并起来。
代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 2e5 + 7;

char s[55];

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int n;scanf("%d",&n);
        vector<int>now;
        int one = 0,zero = 0;
        for(int i = 1;i <= n;i++) {
            scanf("%s",s + 1);
            int len = strlen(s + 1);
            now.push_back(len / 2 * 2);
            for(int j = 1;j <= len;j++) {
                if(s[j] == '1') {
                    one++;
                } else {
                    zero++;
                }
            }
        }
        
        zero = zero / 2 * 2;
        one = one / 2 * 2;
        
        sort(now.begin(),now.end());
        int ans = n;
        for(int i = 0;i < now.size();i++) {
            if(zero >= now[i]) {
                zero -= now[i];
            }
            else if(one >= now[i]) {
                one -= now[i];
            }
            else if(zero + one >= now[i]){
                if(zero >= one) {
                    zero -= now[i] - one;
                    one = 0;
                }
                else {
                    one -= now[i] - zero;
                    zero = 0;
                }
            }
            else {
                ans--;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

感想:B题以前弄VB的时候好像见过,但一开始还是想直接冒泡上去,WA之后重新考虑了奇偶数之间的关系。C题再调的时候一开始是用continue,但案例都不行,换成i++就行了,就挺烦的。感觉状态有点崩,明天打完之后要好好调一下了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值