2023 Benelux Algorithm Programming Contest (BAPC 23)
A - \texttt
题意
\(n\)个软件包,已知大小,可以同时下载\(k\)个,已经下载好了\(m\)个,选\(k\)个下载使得下载完后进度最大,输出已完成进度所占百分比。
思路
选最大的\(m+k\)个。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n, m, k;
cin >> n >> m >> k;
vector<int> v(n);
int sum = 0;
for (int i = 0; i < n; i++)
{
cin >> v[i];
sum += v[i];
}
if (n == m || n <= k || m + k >= n)
{
cout << fixed << setprecision(12) << 100.00000000000 << endl;
return;
}
sort(v.begin(), v.end(), greater<int>());
int t = 0;
for (int i = 0; i < m + k; i++)
{
t += v[i];
}
cout << fixed << setprecision(15) << t * 1.0 / sum * 100.0 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
B - Battle Bots
题意
给定\(n\),有两种操作:\(n = \frac n 2\)和\(n = n - 1\)。求使得\(n = 0\)的最少操作数。
思路
一直除\(2\)直到\(1\)再减\(1\)即可。注意开\(long\ double\)否则精度不够。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
long double n;
cin >> n;
int ans = 0;
while (n > 1)
{
n /= 2;
ans++;
}
cout << ans + 1 << endl; // 最后的-1
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
D - Democratic Naming
题意
给\(n\)个长度为\(m\)的字符串,找出每位出现次数最多的字符。
思路
开个桶。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mxn = 1e3 + 5;
int tong[mxn][35];
void solve()
{
int n, m;
cin >> n >> m;
vector<string> A(n + 1);
for (int i = 0; i < n; ++i)
{
cin >> A[i];
}
for (int i = 0; i < m; ++i)
{
for (int j = 0; j < n; ++j)
{
tong[i][A[j][i] - 'a']++;
}
}
for (int i = 0; i < m; ++i)
{
int maxn = 0;
for (int j = 0; j <= 30; ++j)
{
maxn = max(maxn, tong[i][j]);
}
char ch = (char)('z' + 1);
for (int j = 0; j <= 30; ++j)
{
if (tong[i][j] == maxn)
{
if (ch > 'a' + j)
{
ch = (char)('a' + j);
}
}
}
cout << ch;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
E - Exam Study Planning
题意
\(n\)场考试,已知考试的开始时间、如果准备了考试的结束时间、没准备考试的结束时间以及准备考试需要的时间。问最多能通过几场考试。
思路
每场考试两种状态,准备/不准备,二者分别对应不同的权值。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mxn = 2e3 + 5;
int dp[mxn][mxn]; // dp[i][j]表示第i场考试结束后通过j场考试所需的最早时间
void solve()
{
int n;
cin >> n;
vector<int> st(n + 5), ed1(n + 5), ed2(n + 5), c(n + 5);
for (int i = 1; i <= n; i++)
{
cin >> st[i] >> ed1[i] >> ed2[i] >> c[i];
}
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
{
dp[i][j] = -1e18;
}
}
dp[0][0] = st[1];
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= i; j++)
{
//当前考试不准备
dp[i][j] = max(dp[i][j], dp[i - 1][j] + (i == n ? 0 : st[i + 1] - ed2[i]));
if (!j)
{
continue;
}
// 准备了且时间足够
if (dp[i - 1][j - 1] >= c[i])
{
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + (i == n ? 0 : st[i + 1] - ed1[i]) - c[i]);
}
}
}
for (int i = n; i >= 0; i--)
{
if (dp[n][i] >= 0)
{
cout << i << endl;
return;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
F - Funicular Frenzy
题意
思路
代码
点击查看代码
G - Geometry Game
题意
给\(4\)个点的坐标,问它们围成的封闭图形是正方形、菱形、矩形、平行四边形、梯形、筝形还是都不满足。
思路
用除法有精度损失,把边转化成向量来解决。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define int ll
struct Vector
{
int x, y;
};
void solve()
{
int x1, y1, x2, y2, x3, y3, x4, y4;
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
//边长平方
int l1 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
int l2 = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
int l3 = (x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4);
int l4 = (x1 - x4) * (x1 - x4) + (y1 - y4) * (y1 - y4);
//向量
Vector a = { (x1 - x2), (y1 - y2) };
Vector b = { (x3 - x2), (y3 - y2) };
Vector c = { (x3 - x4), (y3 - y4) };
Vector d = { (x1 - x4), (y1 - y4) };
if (l1 == l3 && l2 == l4 && a.x * c.y == a.y * c.x && b.x * d.y == b.y * d.x)//对边相等且平行
{
if (l1 == l2)//邻边相等
{
if (a.x * b.x + a.y * b.y == 0)//有直角,正方形
{
cout << "square";
return;
}
cout << "rhombus";//菱形
return;
}
if (a.x * b.x + a.y * b.y == 0)//除了正方形,有直角——矩形
{
cout << "rectangle";
return;
}
cout << "parallelogram";//剩下的是平行四边形
return;
}
if (a.x * c.y == a.y * c.x || b.x * d.y == b.y * c.x)//有一组对边平行——梯形
{
cout << "trapezium";
return;
}
if ((l1 == l2 && l3 == l4) || (l2 == l3 && l4 == l1))
{
cout << "kite";
return;
}
cout << "none";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
L - Locking Doors
题意
\(n\)个房间,\(m\)条通路,如果门是开着的,你可以从两边穿过,但每扇门只能从它所连接的两个房间中的一个上锁。最初门都开着,求安装的最少额外出口数量。
思路
首先,对于一个\(SCC\),一定是不需要出口就能关上所有门。问题就转化成求有多少个没有出边的\(SCC\)。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mxn = 1e6 + 5;
vector<int> g[mxn];
int dfn[mxn], low[mxn], id[mxn], sz[mxn];
stack<int> s;
bool inst[mxn];
int cnt, tot;
void tarjan(int u)
{
dfn[u] = low[u] = ++tot;
s.push(u);
inst[u] = true;
for (int v = 0; v < g[u].size(); v++)
{
if (dfn[g[u][v]] == 0)
{
tarjan(g[u][v]);
low[u] = min(low[u], low[g[u][v]]);
}
else if (inst[g[u][v]])
{
low[u] = min(low[u], dfn[g[u][v]]);
}
}
if (low[u] == dfn[u])
{
cnt++;
int v;
do {
v = s.top();
s.pop();
inst[v] = false;
id[v] = cnt;
sz[cnt]++;
} while (v != u);
}
}
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
}
for (int i = 1; i <= n; i++)
{
if (dfn[i] == 0)
{
tarjan(i);
}
}
int ans = 0;
vector<bool> vis(cnt + 1, false);
for (int u = 1; u <= n; u++)
{
for (int v : g[u])
{
if (id[u] != id[v]) // 如果u和v不属于同一个SCC
{
vis[id[v]] = true; // 标记SCC[id[v]]有出边
}
}
}
for (int i = 1; i <= cnt; i++)
{
if (!vis[i])
{
ans++;
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}