The 2024 ICPC Asia EC Regionals Online Contest (II)
A - Gambling on Choosing Regionals#
题意#
场比赛,每场比赛每个大学至多 个队;总 个队伍,每队有分数与所属大学两个属性,每只队伍至多参加 场比赛。求各个队在最坏情况下的最优排名。
思路#
最坏情况就是你打哪场,强队都去哪场,就选
小的场次,能让排名更靠前。对于每队能打两场,最坏情况,两场强队都跟着你,故考虑一场即可。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct group
{
int id, sc;
string ut;
bool operator < (const group a)
{
return sc > a.sc;
}
};
void solve()
{
int n, k, minn = LLONG_MAX;
cin >> n >> k;
for (int i = 0; i < k; i++)
{
int x;
cin >> x;
minn = min(minn, x); // 人最少的场次
}
vector<group> v(n);
for (int i = 0; i < n; i++)
{
cin >> v[i].sc >> v[i].ut;
v[i].id = i;
}
sort(v.begin(), v.end()); // 按分数降序排
map<string, int> cnt;
vector<int> ans(n);
int cur = 0;
for (int i = 0; i < n; i++)
{
if (cnt[v[i].ut] < minn) // v[i]所属大学的名额还有
{
cur++;
cnt[v[i].ut]++;
}
ans[v[i].id] = cur;
}
for (int i = 0; i < n; i++)
{
cout << ans[i] << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}
F - Tourist#
题意#
初始值
,给 个数,相加后问能否 ,能则输出在第几次恰好 ,否则输出- 。
思路#
模拟。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n, sum = 1500;
cin >> n;
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
sum += x;
if (sum >= 4000)
{
cout << i + 1 << endl;
return;
}
}
cout << -1 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}
G - Game#
题意#
与 玩游戏,最初各有 。 的筹码,各自赢的概率为 、 ,平局概率为 。平局时立刻进行下一局;当赢家的筹码 输家的,游戏结束,此时的赢家获胜;每局的输家要失去赢家此时的筹码数。问 最后获胜的概率。
思路#
其实只用考虑3种情况:
、 、 ,然后递归,加上辗转相除递归次数不会很多。除法用逆元处理。对于 的情况, 可以连赢 次(记这部分概率为 ),然后接着递归;也可能在中途就输了,此时的概率就是 ,则最后的概率就是 。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int x, y, a, b, c, p0, p1, p2;
int qpow(int base, int x) // 快速幂
{
int res = 1;
while (x)
{
if (x & 1)
{
res *= base;
res %= mod;
}
x >>= 1;
base *= base;
base %= mod;
}
return res;
}
int dfs(int x, int y)
{
if (x == y) // 筹码一样输了就死
{
return p0;
}
if (x < y) // 筹码少,只能一直赢
{
int cnt = y / x;
if (y % x == 0)
{
cnt--; // 留一次判最后的 x == y
}
return (dfs(x, y - x * cnt) * (qpow(p0, cnt) % mod)) % mod;
}
int cnt = x / y;
if (x % y == 0)
{
cnt--;
}
return ((dfs(x - y * cnt, y) - 1 + mod) % mod * qpow(p1, cnt) % mod + 1) % mod;
}
void solve()
{
cin >> x >> y >> a >> b >> c; // 赢的概率是 a / c 和 b / c
c = a + b; // 除去平局
// 逆元
p0 = a * qpow(c, mod - 2) % mod; // A赢
p1 = b * qpow(c, mod - 2) % mod; // B赢
cout << dfs(x, y) << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
I - Strange Binary#
题意#
给定非负整数
,问是否能构造出序列 使得 ,其中 满足: 。有则输出任意满足要求的序列,否则输出 。
思路#
对于
,它代表的就是第 位上的 ( 位每一位上只有1个 ),所以 必定是 ,否则结果就一定是负数。而显然 等价于 所以每个 结构都能这样凑出来,即对于第 位的 ,可以转化成 ,此时 ,这时又可以将第 位上的 抵消。构造过程中发现, 的倍数(末尾有两个以上连续的 ),或者中间有两个以上连续的 ,不能构造。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n;
cin >> n;
vector<int> a(32);
int idx = 0;
while (n)
{
if (n & 1)
{
a[idx++] = 1;
}
else
{
a[idx++] = 0;
}
n >>= 1;
}
for (int i = 0; i <= 30; i++)
{
if (a[i] == 1 && a[i + 1] == 0) // 0,1可以凑成1,-1
{
a[i + 1] = 1;
a[i] = -1;
}
}
for (int i = 0; i < 31; i++)
{
if (a[i] == 0 && a[i + 1] == 0) // 非法
{
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
for (int i = 0; i <= 31; i++)
{
cout << a[i] << ((i + 1) % 8 ? " " : "\n");
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
J - Stacking of Goods#
题意#
个物品,每个物品有重量 、体积 和可压缩度 三种属性。你要讲物品堆叠,一个物品在堆叠后的体积是 ,其中 是其上方所有物品的重量之和。求所有物品堆叠后总体积的最小值。
思路#
对于一个物品,它的体积不会受其上方物品顺序的变化影响(
始终不变),用微扰法可证明只需按 升序排列即是最优:交换第 个和第 个物品,二者的体积分别变为 和 ,则 ,得 ,当 ,即 时, ,即一旦顺序改变,总体积增加,故按照 升序排列即是最优。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct goods
{
int w, v, c;
bool operator < (const goods a)
{
return c * 1.0 / w < a.c * 1.0 / a.w; // 此处换为乘法最好
}
};
void solve()
{
int n, ans = 0, W = 0;
cin >> n;
vector<goods> v(n);
for (int i = 0; i < n; i++)
{
cin >> v[i].w >> v[i].v >> v[i].c;
ans += v[i].v;
}
sort(v.begin(), v.end());
for (int i = 0; i < n; i++)
{
ans -= W * v[i].c;
W += v[i].w;
}
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;
}
L - 502 Bad Gateway#
题意#
给定
,有两种操作: ,或重置为 ,求最优策略下,减少到 的期望步数。
思路#
么最优的策略一定是选择一个阈值
,开始不停重置,一旦重置到一个小于 的
数就直接减到。设重置到小于 c 的数的概率为 ,根据期望线性性拆解到计算重置 次的概率之和,那么这个策略下的期望步数为: 。
对勾函数形式,最小值在或 处取得。
代码#
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int gcd(int a, int b)
{
return (b ? gcd(b, a % b) : a);
}
void solve()
{
int t;
cin >> t;
int a = ceil(sqrt(2.0 * t));
int b = floor(sqrt(2.0 * t));
// 题目要求分式形式
int na = 2 * t + a * (a - 1), da = 2 * a;
int nb = 2 * t + b * (b - 1), db = 2 * b;
if (na *db < nb * da)
{
int _gcd = gcd(na, da);
cout << na / _gcd << ' ' << da / _gcd << endl;
}
else
{
int _gcd = gcd(nb, db);
cout << nb / _gcd << ' ' << db / _gcd << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧