首页 > 其他分享 >2024 ICPC National Invitational Collegiate Programming Contest, Wuhan Site

2024 ICPC National Invitational Collegiate Programming Contest, Wuhan Site

时间:2024-05-09 14:44:07浏览次数:26  
标签:std Invitational val 罪罚 Contest int LL cnt Wuhan

目录

写在前面

补题地址:https://codeforces.com/gym/105143

正式赛全程犯大病打铜了呃呃,以下按个人向难度排序。

AIEEEEE!忍者为何!队长=san 实际战犯!罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罪罚罚罪罚罪罚罪罚罪罚罪罚罪罚

南无阿弥陀佛……不由得土下座……只得切断谢罪!庸碌大半生,邀请赛取我性命,再无意难平。撒由那拉!

「2024·ICPC·National·Invitational·Collegiate·Programming·Contest, Wuhan·Site 电子狂言俳句乱舞·殒命珞珈山上」#1 完

I

签到。

场上 dztle 大神一眼秒了。

首先忽略初始时就位于原串最右侧的 1。

发现最优的策略是每次将不位于字符串最右侧的、最右侧的连续一段 1 调整到字符串最右侧,于是仅需统计此时字符串中有多少段连续的 1 即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  std::string s; std::cin >> s;
  while (s.back() == '1') s.pop_back();

  int cnt = 0;
  for (int i = 0, lst = -2, len = s.length(); i < len; ++ i) {
    if (s[i] == '1') {
      if (lst != i - 1) ++ cnt;
      lst = i;
    }
  }
  std::cout << cnt;
  return 0;
}

B

贪心。

赛时这题一直想怎么均分所有数想了一堆假做法挂了三发纯战犯。然后 dztle 看了一眼秒了,紫砂了。

首先发现 \(n\) 次操作实际上可以将整个数列调整成任意形态,于是仅需考虑如何分配 \(\sum a_i\) 得到最终答案的形态即可。

考虑枚举二进制位从高位向低位贪心,一个显然的想法是尽可能不让高位在答案中出现,于是考虑答案中是否可以不出现某位。

对于第 \(i(0\le i\le \log v)\) 位,若可以仅通过之后的若干位构造出 \(n\) 个和为 \(\sum a_i\) 的数,即满足 \(\sum a_i\le n\times (2^{i} - 1)\),则该位是不必要的;否则必定有一个数该位为 1,则应尽可能地令所有数该位均为 1,从而减少使用之后若干位构造的负担。

按照上述思路贪心地分配即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int n; std::cin >> n;
  LL sum = 0, ans = 0;
  for (int i = 1; i <= n; ++ i) {
    int x; std::cin >> x;
    sum += x;
  }
  for (LL i = 30; i >= 0; -- i) {
    LL j = (1ll << i);
    if (sum <= 1ll * n * (j - 1)) continue;
    ans += j;
    sum -= 1ll * std::min(1ll * n, sum / j) * j;
  }
  std::cout << ans;
  return 0;
}

K

找规律。

打表题,场上替 dztle 大神打了个表大神一眼秒了,本场唯一的贡献。

发现有:

\[\bigoplus_{i=1}^{n} i = \begin{cases} n&(n\bmod 4 = 0)\\ 1 &(n\bmod 4 = 1)\\ n + 1 &(n\bmod 4 = 2)\\ 0&(n\bmod 4 = 3)\\ \end{cases}\]

喜欢证明可以参考:https://www.cnblogs.com/Mychael/p/8633365.html

则当 \(n=0\) 时先手拿 \(n\) 必胜,\(n=1\) 时先手拿 \(1\) 必胜。

当 \(n=3\) 时先手无法操作必败,\(n=4\) 时先手无论如何操作,后手取走另一侧均会获胜,则先手必败。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  // for (int i = 1, s = 0; i <= 100; ++ i) {
  //   s ^= i;
  //   std::cout << i << " " << s << "\n";
  // }
  int T; std::cin >> T;
  while (T --) {
    int n; std::cin >> n;
    if (n % 4 == 0 || n % 4 == 1) std::cout << "Fluttershy\n";
    else std::cout << "Pinkie Pie\n";
  }
  return 0;
}

F

交互,单调性。

这个矩阵的形态学名叫杨氏矩阵[1],在算法作业上见过并且当时发现了下述结论[2]于是跟队友说了下,可能对场上出了本题有了一点贡献,本场唯 1.0001 的贡献。

发现对于某个权值 \(v\),其在每一行的所有出现位置一定构成一段连续的区间。且其在第 \(i\) 行与第 \(i+1\) 行中出现的位置构成的区间 \([l_i, r_i], [l_{i + 1}, r_{i + 1}]\) 一定满足:

\[l_{i + 1}\le l_{i}\le r_{i + 1} \le r_{i} \]

即有:

\[(l_{i + 1}\le l_i)\land (r_{i + 1}\le r_i) \]

发现 \(l_1\sim l_n\) 和数列 \(r_{1}\sim r_n\) 均为非递减数列,构成了一个阶梯形,以该阶梯形为分界,左上为小于 \(v\) 的所有位置,右下为大于 \(v\) 的所有位置,则权值 \(v\) 的排名即为右下角位置的数量。

由阶梯形这个性质,求每种权值 \(v\) 的排名,可以考虑维护一个初始位于最后一行左侧的指针,倒序枚举每行,并维护指针使之指向第一个大于 \(v\) 的元素,即可统计每行有多少数大于 \(v\) 从而得到排名。发现该过程中指针仅会单调右移和上移 \(O(n)\) 次。

解决了对任意权值求排名的问题,仅需在外层加个二分答案枚举权值即可解决本题。值域为 \(O(n^2)\) 级别,则总时间复杂度 \(O(n\log n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
int n, k, ans;
//=============================================================
int query(int x_, int y_, int val_) {
  std::cout << "? " << x_ << " " << y_ << " " << val_ << "\n";
  std::cout.flush();

  int ret; std::cin >> ret;
  return ret;
}
bool check(int lim_) {
  int s = 0;
  for (int x = n, y = 1; x; -- x) {
    while (y <= n && query(x, y, lim_) == 1) ++ y;
    s += n - y + 1;
  }
  return s < k;
}
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  // std::ios::sync_with_stdio(0), std::cin.tie(0);
  std::cin >> n >> k;
  for (int l = 1, r = n * n; l <= r; ) {
    int mid = (l + r) >> 1;
    if (check(mid)) {
      r = mid - 1;
      ans = mid;
    } else {
      l = mid + 1;
    }
  }
  std::cout << "! " << ans;
  return 0;
}

M

贪心。

因为是字典序比较,于是仅需关注在当前数列中如何合成出最大的一个数。

发现每次合并都需要一个奇数和一个偶数并合成一个新的奇数,则考虑将所有偶数降序排序,枚举当前合成最大的数的最后一步中所需的偶数 \(x\),检查能否合成出奇数 \(x + 1\) 或 \(x - 1\) 即可。显然,若无法得到这两个奇数,说明无法合成大于等于 \(2\times x - 1\) 的数,则偶数 \(x\) 一定不会参与之后的合并。

又发现合并得到一个数 \(v\) 所需的原数列中的数实际上可以递归求得,且个数至多为 \(O(\log v)\) 级别,于是可以考虑递归地检查能否得到某个数。具体地:

  • 若原数列中存在 \(v\),则合法。
  • 否则若 \(v\) 为偶数或 \(v\) 为 1,则 \(v\) 无法被合成,非法。
  • 否则若 \(v\) 为奇数,递归地检查能否同时得到 \(\left\lfloor\frac{v}{2}\right\rfloor\) 与 \(\left\lfloor\frac{v}{2}\right\rfloor + 1\) 即可。

特别注意上述第三条中的条件同时,即最终递归求得的所需的各种数的数量,不得大于原数列中对应数的数量。于是需要在上述过程中哈希表维护原数列中每种权值的出现次数,在上述检查过程中需要动态维护每个数出现次数,若检查失败需要还原哈希表。最后输出答案时仅需输出哈希表中所有元素即可。

偷懒写个 unordered_map,总时间复杂度 \(O(n\log v)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n;
std::unordered_map<LL, int> cnt;
std::vector<LL> even, modified, ans;
//=============================================================
int count(LL val_) {
  if (!cnt.count(val_)) return 0;
  return cnt[val_];
}
void add(LL val_) {
  if (!cnt.count(val_)) cnt[val_] = 0;
  ++ cnt[val_];
}
void sub(LL val_) {
  -- cnt[val_];
  if (cnt[val_] == 0) cnt.erase(val_);
  modified.push_back(val_);
}
bool get(LL val_) {
  if (count(val_)) return sub(val_), true;
  if (val_ == 1 || val_ % 2 == 0) return false;
  return (get(val_ / 2ll) && get(val_ / 2ll + 1));
}
bool check(LL val_) {
  modified.clear();
  if (get(val_)) return true;

  for (auto x: modified) add(x);
  return false;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  std::cin >> n;
  for (int i = 1; i <= n; ++ i) {
    LL a; std::cin >> a;
    if (a % 2 == 0) even.push_back(a);
    add(a);
  }
  std::sort(even.begin(), even.end(), std::greater<LL>());
  for (auto x: even) {
    if (!count(x)) continue;
    sub(x);
    if (check(x + 1)) {
      add(2ll * x + 1);
    } else if (check(x - 1)) {
      add(2ll * x - 1);
    } else {
      add(x);
    }
  }
  for (auto x: cnt) {
    for (int i = 1; i <= x.second; ++ i) {
      ans.push_back(x.first);
    }
  }
  std::cout << ans.size() << "\n";
  for (std::vector<LL>::reverse_iterator it = ans.rbegin(); it != ans.rend(); ++ it) {
    std::cout << *it << " ";
  }
  return 0;
}
/*
4
1 1 2 2 4 
*/

E

D

C

写在最后

给 dztle 大神磕四个四题全是大神出的我纯拖后腿的飞舞一个。

撒由那拉!

参考:


  1. https://oi-wiki.org/math/young-tableau/ ↩︎

  2. https://www.cnblogs.com/rainycolor/p/18080157 ↩︎

标签:std,Invitational,val,罪罚,Contest,int,LL,cnt,Wuhan
From: https://www.cnblogs.com/luckyblock/p/18182238

相关文章

  • AtCoder Beginner Contest 352
    AtCoderBeginnerContest352A-AtCoderLine给\(N,X,Y,Z\)判断是否\(\min(X,Y)\leZ\le\max(X,Y)\)。模拟。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,x,y,z;signedmain(){ cin>>n>>x>>y>......
  • AtCoder Grand Contest 001
    D.ArraysandPalindrome如果两个字符要求相同就给它们连边,对于一个长度为\(x\)的回文串,\(x\)是偶数会连\(x/2\)条边,奇数会连\(x/2-0.5\)条边。\(a\)和\(b\)两个序列总和为\(2n\),要让\(n\)个字符相同至少连\(n-1\)条边,也就是奇数个数超过\(2\)时一定无解......
  • AtCoder Beginner Contest 352题解
    AtCoderBeginnerContest352Time:2024-05-04(Sat)20:00-2024-05-04(Sat)21:40AAtCoderLine问题陈述AtCoder铁路线有$N$个车站,编号为$1,2,\ldots,N$。在这条线路上,有趟进站列车从$1$站出发,依次停靠$2,3,\ldots,N$站,有趟出站列车从$N$站出发,依次停......
  • AtCoder Beginner Contest 352 考试总结
    前言正常发挥。属于是\(4\)个月没搞OI,复健成功了!得分明细:ABCDEFGTotal√√√√√××1475改题明细:ABCDEFG√√√√√××第一次正式rated打AT,行吧!A.AtCoderLineProblemAtCoder铁路线有\(N\)个车站,编号为\(1......
  • AtCoder Beginner Contest 351
    A-Thebottomoftheninth(abc351A)题目大意给定\(9\)个\(a_i\)和\(8\)个\(b_i\),问最后一个\(b_9\)是多少,使得\(\suma_i<\sumb_i\)。解题思路答案就是\(\suma_i-\sumb_i+1\)。神奇的代码a=sum(map(int,input().split()))b=sum(map(int,input().......
  • 2023-2024 ICPC German Collegiate Programming Contest (GCPC 2023)
    B.BalloonDarts首先上一些计算几何的板子。如果\(k\)条直线覆盖\(n\)个点成立的,则有两种情况。如果\(n\lek\)则一定成立,反之在前\(k+1\)个点中必然存在两个点被一条直线经过,我们可以枚举出这条直线,然后暴力的删掉点,然后递归做。#include<bits/stdc++.h>usingnamespaces......
  • 2020-2021 ICPC NERC (NEERC), North-Western Russia Regional Contest (Northern Sub
    E-EasyCompare-and-Set题意给定n个条件,如果存在一个合法序列使得这n个判断条件成立,则输出Yes和这个合法序列,否则输出No。分析首先可以发现对于\(w_i=0\)的操作我们可以在处理完\(w_i=1\)的操作之后讨论一下即可。发现\(a_i\)和\(b_i\)很大需要对其进行离散化操作。离......
  • AtCoder Beginner Contest 351
    B-SpottheDifference难度:⭐题目大意给定两个矩阵,找不同解题思路数据很小,暴力就行;神秘代码#include<bits/stdc++.h>#defineintunsignedlonglong#defineIOSios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#defineendl'\n'usingnamespa......
  • AtCoder Beginner Contest 208 E
    E-DigitProducts点击查看代码map<int,int>f[20];voidsolve(){intn,k;cin>>n>>k;autos=to_string(n);intm=s.size();function<int(int,int,int,int)>dfs=[&](inti,intlimit,intis_num,intmul)->int{if(i......
  • 2018-2019 ACM-ICPC, China Multi-Provincial Collegiate Programming Contest
    A.MaximumElementInAStack按照题目模拟就好,栈内的最大值可以维护单调栈解决。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;usingui32=unsignedint;ui32SA,SB,SC;ui32rng61(){SA^=SA<<16;SA^=SA>>5;SA^......