Loading

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







比赛链接 https://codeforces.com/gym/104790

posted @ 2024-10-12 08:34  _SeiI  阅读(35)  评论(0编辑  收藏  举报