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