2024 暑假友谊赛 1

2024 暑假友谊赛 1

2024.7.13 9:00————12:00

过题数2/9
补题数5/9

  • AtCoder - abc204_d
  • AtCoder arc092_a
  • CodeForces 1551D1
  • AtCoder abc123_d
  • AtCoder arc078_b
  • CodeForces 448D
  • CodeForces 1618F
  • AtCoder abc265_a
  • AtCoder abc207_e

A - Cooking

一道很典型的dp题,但我不会,当时是搜板子做的,算法几乎都不会。
题解:
n个盘子,尽量均等的分成俩份即可。
01dp,每个盘子有取或不取的情况。
代码:

#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>

using namespace std;
#define int long long
int t[105];
int a[1005];
int b[1005];
int c[1005];

signed main() {
    int n;
    cin >> n;
    int res = 0;
    int ans = 1e9;
    for (int i = 0; i < n; i++) {
        cin >> t[i];
        res += t[i];
    }
    vector<vector<int>>dp;
    //前i个盘子占用第一个烤箱j时间
    for (int i = 0; i <= n; i++) {
        vector<int>tmp;
        for (int j = 0; j <= res/2; j++) {
            tmp.push_back(0);
        }
        dp.push_back(tmp);
    }//赋初值

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= res/2; j++) {
            if(j >= t[i-1]) {
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-t[i-1]]+t[i-1]);
                //第i个要不要取
            }
            else dp[i][j] = dp[i-1][j];
            //时间已经超过,直接不取
        }
    }//循环一定要注意,状态方程比较容易,注意循环
    ans = res - dp[n][res/2];
    //输出俩个烤箱的较大值
    cout << ans << endl;

    return 0;
}

B - 2D Plane 2N Points

题解:
给出n组红点和蓝点,求最多有多少组红点的x,y都小于蓝点,每个点只能用一次。
红点从大到小排序,蓝点从小到大排序,开始遍历,找到符合条件的蓝点的最小y组队,因为红点的x在逐渐变小,所以符合条件的蓝x会越来越多,就需要尽可能大的y。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
#define double long double
int t[104];
int xs[4][105];
bool st[105];

signed main() {
    int n;
    cin >> n;
    vector<pair<int,int>>ab,cd;

    for (int i = 0; i < n; i++) {
        int a,b;
        cin >> a >> b;
        ab.push_back({a,b});
    }sort(ab.begin(),ab.end(),greater<>());
    //从大到小排序
    for (int i = 0; i < n; i++) {
        int c,d;
        cin >> c >> d;
        cd.push_back({c,d});
    }sort(cd.begin(),cd.end());
    
    int ans = 0;
    memset(st,1,sizeof st);

    for (int i = 0; i < ab.size(); i++) {
        int ls = -1;
        for (int j = 0; j < cd.size(); j++) {
            if(!st[j])continue;
            if(cd[j].first <= ab[i].first || cd[j].second <= ab[i].second) {
                continue;
            }
            if(ls == -1) {
                ls = j;
            }
            if(ls != -1 && cd[j].second < cd[ls].second)ls = j;
        }//这一段比较关键,但不难懂,注意一下即可。
        if (ls != -1) {
            st[ls] = false;
            ans++;
        }
    }

    cout << ans << endl;
    return 0;
}


D - Cake 123

哦蛋糕,本来都要做出来了,差点地方没想到
题解:
给定x个a,y个b,z个c。求各取一个从最大和开始输出k个。
俩个二重循环,先a+b,排序,然后前k个与c相加,排序。
挺有意思的地方是直接遍历,非常规方法,在三重循环中间判断个数是否小于等于k,直接插入vector也可,不判断的话会re。
代码:

#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>

using namespace std;
#define int long long
int a[100005];
int b[100005];
int c[100005];
int sum[100000005];
int ans[40000000];

signed main() {
    int x,y,z,k;
    cin >> x >> y >> z >> k;
    for (int i = 1; i <= x; i++)cin >> a[i];
    for (int i = 1; i <= y; i++)cin >> b[i];
    for (int i = 1; i <= z; i++)cin >> c[i];
    sort(a+1,a+x+1);
    sort(b+1,b+y+1);
    sort(c+1,c+z+1);
    int p = 1;
    for (int i = 1; i <= x; i++) {
        for(int j = 1; j <= y; j++) {
            sum[p++] = a[i] + b[j];
        }
    }
    sort(sum+1,sum+p,greater<>());
    int aaa = 1;
    for (int  i = 1; i <= min(k,p-1); i++) {
        for (int j = 1; j <= z; j++) {
            ans[aaa++] = sum[i] + c[j];
        }
    }sort(ans+1,ans+aaa,greater<>());
    for (int i = 1; i<= k; i++) {
        cout << ans[i] << endl;
    }
    return 0;
}

F - Multiplication Table

题解:
n*m的数组,对应位置就是横纵坐标之积,找到第k大的数字并输出。
二分求解,能否找到k个比它小的数字,再找比它小的数字时,可以以横坐标遍历,找到有几个j满足条件即可。
代码:

#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>

using namespace std;
#define int long long
int n,m,k;
vector<vector<int>>a;

bool check(int x) {
    int res = 0;
    int ls;
    for (int i = 1; i <= n; i++) {
        ls = min(m,x/i);
        //最多有几个ls满足条件
        while(i*ls >= x)ls--;
        //保障邻界条件
        res += ls;
        //第i行有ls个满足条件
    }
    return res < k;
}

signed main() {
    cin >> n >> m >> k;
    int l = 1,r = n*m;
    while (l <r) {
        int mid = (l+r+1)/2;
        if (check(mid))l = mid;
        else r = mid-1;
    }//res<k的最大值
    cout << l << endl;
    return 0;
}


H - Apple

a这题感觉是这次比赛的唯一一道简单题了
题解:
买一个苹果要x元,买3个苹果要y元,现在需要刚好购买n哥苹果且花费最少。
直接计算即可,注意单独买三个苹果比合体买三个苹果要便宜的情况。
代码:

#include<iostream>
#include<algorithm>

using namespace std;
#define int long long

signed main() {
    int x,y,n;
    cin >> x >> y >> n;
    int ans = 0;
    if (x*3 > y)ans = n/3*y + n%3*x;
    else ans = n*x;
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值