2021.10.13 训练

A - Drinks Choosing

题意:

有n个学生,已知他们各自喜欢的饮料的编号(1~k), 有n/2(向上取整)份饮料,一份可以满足一个或两个相同的饮料需求。
问最多能满足多少个学生的需求。

分析:

思维题。将每种饮料的需求个数计数。一份可以满足一个或两个相同的饮料需求,则为了使每一份饮料发挥最大作用(不被浪费),就尽量先满足需求为偶数个的饮料需求,然后再考虑奇数。

代码:

#include<algorithm>
#include<cstdio>
#include<iostream>
#include<stdlib.h>
#include<cstring>
#include<map>
using namespace std;

typedef long long ll;

int n,k;

int main(){ //有些混乱
    ios::sync_with_stdio(false);
    cin>>n>>k;
    int a[k+1];
    int num;
    int m=(n+1)/2;
    memset(a,0,sizeof(a));
    for(int i=0;i<n;i++){
        cin>>num;
        a[num]++;
       // cout<<" "<<a[num]<<endl;
    }
    int flag=0,ans=0;
    for(int i=1;i<=k;i++){
       // cout<<a[i]<<endl;
        if(a[i]%2==0){
            if(m-a[i]/2>0){
                ans+=a[i];
                m=m-a[i]/2;
            }
            else{
                ans+=m*2;
                m=0;
                break;
            }
        }
    }

    for(int i=1;i<=k;i++){
        if(m==0) break;
        if(a[i]%2!=0){
            if(m-a[i]/2>0){
                ans+=a[i]-1;
                m=m-a[i]/2;
            }
            else{
                ans+=m*2;
                m=0;
                break;
            }
        }
    }
    if(m!=0) ans+=m;
    cout<<ans<<endl;
    return 0;
}

//int n, k, num;  //看到的比较简单思路清晰的做法
//  map<int,int>mp;
//int main(){
//  ios::sync_with_stdio(false);
//  cin>>n>>k;
//  for(int i=0; i<n; i++){
//    cin >>num;
//    mp[num]++;
//  }
//  int a=0,b=0,ans=0;
//  for(auto it: mp){
//    b+=it.second%2;
//    a+=it.second/2*2;
//  }
//  ans=a+(b+1)/2;
//  cout << ans << endl;
//  return 0;
//}

B - Sport Mafia

题意:

有一个空盒,可以里面放糖果,依次递增的放糖(eg:第一次放1颗,下一次放2颗…第n次放n颗); 也可以从里面取糖果,但是一次只能取1颗。
n次操作使盒子里的糖果变为k颗,问最多可以取多少次糖果。

分析:

二分。设最多取x次,则有线性关系:((n-x+1)(n-x))/2-x=k,
方程化简:x*x-(2*n+3)*x+n*n+n=2*k,
易得:x*x-2*n*x-x,在(-∞,-b/2*a],即在(-∞,n+3/2]单调递减
x的取值区间为[0,n-1],单调递减,所以用二分可解。
二分缩小区间,确定答案。

代码:
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;

typedef long long ll;


ll k,n;

ll check(ll x)
{
    return x*x-(2*n+3)*x+n*n+n;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    ll l=0,r=n-1,m;
    while(l<=r)
    {
        m=(l+r)/2;
        if(check(m)==2*k)
        {
            cout<<m<<endl;
            break;
        }
        else if(check(m)<2*k) r=m-1;
        else l=m+1;
    }
    return 0;
}

C - Permutation Minimization by Deque

题意:

输入两行n列个数,从中选取若干个数,所选的数不能相邻(上下左右为相邻),求所选的数和的最大值。

分析:

dp。状态转移方程为:
dp[0][i]=max( dp[0][i] , dp[1][i-1]+a[i] )
dp[1][i]=max( dp[1][i] , dp[0][i-1]+b[i] )

代码:
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;

typedef long long ll;

ll dp[2][100005];
ll a[100005],b[100005];
ll n;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    for(int i=0;i<n;i++)
        cin>>b[i];
    dp[0][0]=a[0];
    dp[1][0]=b[0];
    for(int i=1;i<n;i++)
    {
        dp[0][i]=max(dp[0][i-1],dp[1][i-1]+a[i]);
        dp[1][i]=max(dp[1][i-1],dp[0][i-1]+b[i]);
    }
    ll ans=max(dp[0][n-1],dp[1][n-1]);
    cout<<ans<<endl;
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值