2024ICPC网络赛第二场

打印 上一主题 下一主题

主题 844|帖子 844|积分 2532

VP链接
Codeforces:Dashboard - The 2024 ICPC Asia EC Regionals Online Contest (II) - Codeforces
QOJ:The 2024 ICPC Asia East Continent Online Contest (II) - Dashboard - Contest - QOJ.ac
A. Gambling on Choosing Regionals

注意到对于每个队伍来说最坏情况是与所有最强的队一个赛站,那么该队伍的排名会最低,以是为了让自己队伍的排名尽大概地高,最优选择就是去容纳量最小的赛站。
对 c 进行读入的时候只需要记录最小的 c 的值 
,同时利用 unordered_map 记录每一个队伍在学校内的排名,将每个学校前
 支队伍放进一个数组 b 里,再将数组 b 从大到小排序。
输出答案的时候,从头至尾依次遍历每一支队伍

  • 如果队伍在学校的名次小于即是 
    ,该队伍的最优排名就是在数组 b 里的下标
  • 如果队伍在学校的名次大于 
    ,相称于要把同学校的一支队伍移出这个赛站,再将这支队伍放进这个赛站,那么只需要利用二分找出 b 数组中第一个小于该队伍本领的队伍的位置 pos(题目保证每个队伍本领不同,不存在即是的情况),该队伍终极的排名就是 pos - 1(要将其学校前面即本领较强的队伍移出,以是排名要 -1)。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e5 + 10;
  4. int n, k, c, minc = INT_MAX, idx = 0, b[N];
  5. struct node {
  6.         int w, id, rnk = 0;
  7.         bool operator< (const node &x) const {
  8.                 return x.w > w;
  9.         }
  10. } a[N];
  11. unordered_map<string, priority_queue<node>> mp;
  12. inline int read() {
  13.         int x = 0, f = 1; char c = getchar();
  14.         while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
  15.         while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  16.         return x * f;
  17. }
  18. int main() {
  19.         n = read(), k = read();
  20.         for (int i = 1; i <= k; i++) c = read(), minc = min(minc, c);
  21.         for (int i = 1; i <= n; i++) {
  22.                 a[i].w = read(), a[i].id = i;
  23.                 string s; char c = getchar();
  24.                 while (c < 'A' || c > 'Z') c = getchar();
  25.                 while (c >= 'A' && c <= 'Z') s += c, c = getchar();
  26.         // 时间限制只有 1s,用 cin 怕 TLE
  27.                 mp[s].push(a[i]);
  28.         }
  29.         for (auto& [x, q] : mp) {
  30.                 int num = 0;
  31.                 while (!q.empty()) {
  32.                         node cur = q.top(); q.pop();
  33.                         a[cur.id].rnk = ++num; // 记录排名
  34.                         if (num <= minc) b[++idx] = a[cur.id].w;
  35.                 }
  36.         }
  37.         sort(b + 1, b + idx + 1, greater<int>()); // 从大到小排序
  38.         for (int i = 1; i <= n; i++) {
  39.                 int l = 1, r = idx + 1;
  40.                 while (l < r) {
  41.                         int mid = l + r >> 1;
  42.                         if (b[mid] > a[i].w) l = mid + 1;
  43.                         else r = mid;
  44.                 }
  45.                 if (a[i].rnk <= minc) printf("%d\n", l);
  46.                 else printf("%d\n", l - 1);
  47.         }
  48.         return 0;
  49. }
复制代码
F. Tourist

签到题,按照题意模拟即可。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. int n, c, tot = 1500, ans = -1;
  5. inline int read() {
  6.         int x = 0, f = 1; char c = getchar();
  7.         while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
  8.         while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  9.         return x * f;
  10. }
  11. signed main() {
  12.         n = read();
  13.         for (int i = 1; i <= n; i++) {
  14.                 c = read(), tot += c;
  15.                 if (ans == -1 && tot >= 4000) ans = i;
  16.         }
  17.         printf("%d\n", ans);
  18.         return 0;
  19. }
复制代码
G. Game

可以注意到平局其实是没有用的,以是 Alice 得胜的概率是 
,Bob 得胜的概率是 


证实:
假设
 为 Alice、Bob 在分别有 x、y 个 chips 且每一局的得胜概率分别为 a、b 的条件下,Alice 终极得胜的概率;
 为 Alice 在当前条件下先赢一局,Alice 终极得胜的概率;
 为 Bob 在当前条件下先赢一局且 Alice 终极得胜的概率。
那么有,

移项后有,

终极效果就是,

从这个式子可以得出,每一种情况下,Alice 终极得胜的概率不受平局的影响。

双方的游戏过程现实上是一个辗转相减的过程,可以利用辗转相除来加快。


  • 时,由于 Alice 得胜的情况较多,为方便统计,可以将问题转换成 1 - (Bob 得胜的概率)
  • 当 
     时,可以让 Alice 先连赢 
     次转换成第一种情况。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. const int mod = 998244353;
  5. inline int read() {
  6.         int x = 0, f = 1; char c = getchar();
  7.         while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
  8.         while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  9.         return x * f;
  10. }
  11. int qpow(int x, int k) {
  12.         int res = 1LL;
  13.         while (k) {
  14.                 if (k & 1) res = res * x % mod;
  15.                 x = x * x % mod;
  16.                 k >>= 1;
  17.         }
  18.         return res % mod;
  19. }
  20. int f(int x, int y, int a, int b) {
  21.         if (x == 0) return 0;
  22.         return qpow(a, y / x) * ((1 - f(y % x, x, b, a) + mod) % mod) % mod;
  23. } // 辗转相除求答案
  24. signed main() {
  25.         int t = read();
  26.         while (t--) {
  27.                 int x = read(), y = read(), a0 = read(), a1 = read(), b = read();
  28.                 int inv = qpow(a0 + a1, mod - 2);
  29.                 int A = inv * a0 % mod, B = inv * a1 % mod;
  30.         // 利用费马小定理求 Alice、Bob 获胜概率的乘法逆元
  31.                 printf("%lld\n", f(x, y, A, B));
  32.         }
  33.         return 0;
  34. }
复制代码
I. Strange Binary

所有数字都能进行二进制拆分,由十进制数转换为二进制数,但是大概会由于存在一连的 0 因而不符合题目的条件。
注意到 
,因此对于每一个二进制数,相邻两位如果是 0 1 的话,那么可以将其转换成 1 -1,如许就不会存在一连的 0 了。
但如果该二进制数末端有两个及以上的一连的 0 的时候,即 n 为 4 的倍数 时,那么将无法进行转换使得其满足题目条件。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n, a[32];
  4. inline int read() {
  5.         int x = 0, f = 1; char c = getchar();
  6.         while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
  7.         while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  8.         return x * f;
  9. }
  10. signed main() {
  11.         int t = read();
  12.         while (t--) {
  13.                 n = read();
  14.                 if (n % 4 == 0) {
  15.                         puts("NO");
  16.                         continue;
  17.                 }
  18.                 for (int i = 0; i < 32; i++) a[i] = 0; // 初始化
  19.                 int idx = -1;
  20.                 while (n) {
  21.                         a[++idx] = n & 1;
  22.                         n >>= 1;
  23.                 } // 二进制拆分
  24.                 for (int i = 0; i < 32; i++) {
  25.                         while (i + 1 < 32 && a[i] != 0 && a[i + 1] == 0) {
  26.                                 a[i] = -1, a[i + 1] = 1;
  27.                                 i++;
  28.                         }
  29.                 } // 去 0 操作
  30.                 puts("YES");
  31.                 for (int i = 0; i < 32; i++) {
  32.                         printf("%d ", a[i]);
  33.                         if ((i + 1) % 8 == 0) puts("");
  34.                 } // 输出答案
  35.         }
  36.         return 0;
  37. }
复制代码
J. Stacking of Goods

贪心,考虑所有物品以什么顺序叠放是最优的。
假设有两个相邻的物品 1 和 2(1 在上,2 在下),其对应的重量、体积、压缩系数分别表示为,
 、
 、
 和 
 、
 、
,这两个物品上面的物品重量的和记为 W。两个物品要交换的条件就是,交换后所有物体的终极体积更小。所有物体的终极体积可以表示为,所有物体的总体积 - 每个物体的压缩系数 * 该物体上面所有物体的重量和。由于所有物体的总体积永远稳定,以是要让 每个物体的压缩系数 * 该物体上面所有物体的重量和 尽大概大。
即只需要满足 
,那么就将物体 1 和 2 交换位置(无论这两个物体是否交换位置,对其他物体的压缩体积不会造成任何影响)。化简之后,这个式子就变成了 

要特别注意,有大概会出现一连多个 
 的情况,这种情况下要让重量大的物品放在上面,如许重量大的物品贡献就最多,压缩的体积就更大。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. const int N = 1e5 + 10;
  5. int n;
  6. struct node { int w, v, c; } a[N];
  7. inline int read() {
  8.         int x = 0, f = 1; char c = getchar();
  9.         while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
  10.         while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  11.         return x * f;
  12. }
  13. bool cmp(node x, node y) {
  14.         if (x.c * y.w == x.w * y.c) return x.w > y.w;
  15.         return x.c * y.w < x.w * y.c;
  16. }
  17. signed main() {
  18.         n = read();
  19.         for (int i = 1; i <= n; i++) a[i].w = read(), a[i].v = read(), a[i].c = read();
  20.         sort(a + 1, a + n + 1, cmp); // 排序
  21.         int W = 0, V = 0;
  22.         for (int i = 1; i <= n; i++) {
  23.                 V += a[i].v - a[i].c * W;
  24.                 W += a[i].w;
  25.         } // 记录答案
  26.         printf("%lld\n", V);
  27.         return 0;
  28. }
复制代码
L. 502 Bad Gateway

假设最优的操作是一直进行第二个操作直到数字小于即是 c 以后再进行第一个操作。对于第二个操作,选到小于即是 c 的数的概率是 
,那么盼望的操作时间就是 
。对于第一个操作,由于取到每个数的概率是相等的,以是盼望的操作此时是 
。由于是从第 0 秒开始操作,以是最后的效果是 
,当 
 或 
 的时候这个式子取得最小值。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define int long long
  4. int n, T;
  5. int gcd(int a, int b) { return a == 0 ? b : gcd(b % a, a); }
  6. signed main() {
  7.     ios::sync_with_stdio(false); cin.tie(0);
  8.     cin >> n;
  9.     while (n--) {
  10.         cin >> T;
  11.         int num1 = floor(sqrt(1.0 * 2 * T)), num2 = ceil(sqrt(1.0 * 2 * T));
  12.         int x1 = 2 * T + num1 * (num1 - 1), y1 = 2 * num1;
  13.         int x2 = 2 * T + num2 * (num2 - 1), y2 = 2 * num2;
  14.         int GCD;
  15.         if (x1 * y2 < x2 * y1) {
  16.             GCD = gcd(x1, y1);
  17.             x1 /= GCD, y1 /= GCD;
  18.             printf("%lld %lld\n", x1, y1);
  19.         } else {
  20.             GCD = gcd(x2, y2);
  21.             x2 /= GCD, y2 /= GCD;
  22.             printf("%lld %lld\n", x2, y2);
  23.         }
  24.     }
  25.     return 0;
  26. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

卖不甜枣

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表