首页 > 其他分享 >Codeforces Round #956 (Div. 2) and ByteRace 2024

Codeforces Round #956 (Div. 2) and ByteRace 2024

时间:2024-07-15 19:07:23浏览次数:21  
标签:std kN int cin LL Codeforces 956 2024 now

目录

写在前面

比赛地址:https://codeforces.com/contest/1983

孩子们我回来了。

这场实在是太对胃口,vp 不到 1h 就 4 题了之后 EF 也口出来了,然而赛时睡大觉去了没打真是亏死。

感觉自己的文字能力已经很牛逼了,不需要再多练了,以后的题解都会写得简略些。

A

签到。

令 \(\forall 1\le i\le n, a_i = i\) 即可。

//
/*
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 T; std::cin >> T;
  while (T --) {
    int n; std::cin >> n;
    for (int i = 1; i <= n; ++ i) std::cout << i << " ";
    std::cout << "\n";
  }
  return 0;
}

B

模拟。

有点诈骗的题,让我跑去想牛逼结论。

发现对任意大于 \(2\times 2\) 的矩阵进行的一次操作,都可以等价于若干次对 \(2\times 2\) 矩阵进行的操作。

考虑逐行逐列枚举位置,检查两矩阵是否该位置此时是否相同,若不相同则直接修改以该位置为左上角的 \(2\times 2\) 矩阵,若需要改但无法修改则无解。

显然若有解,则这样直接改肯定能构造出来。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 510;
//=============================================================
int n, m;
std::vector<int> a[kN], b[kN];
//=============================================================
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n >> m;
    for (int i = 0; i < n; ++ i) {
      std::string s; std::cin >> s;
      a[i].clear();
      for (int j = 0; j < m; ++ j) a[i].push_back(s[j] - '0');
    }
    for (int i = 0; i < n; ++ i) {
      std::string s; std::cin >> s;
      b[i].clear();
      for (int j = 0; j < m; ++ j) b[i].push_back(s[j] - '0');
    }
    
    
    int flag = 1;
    for (int i = 0; i < n; ++ i) {
      for (int j = 0; j < m; ++ j) {
        if (a[i][j] != b[i][j]) {
          if (i + 1 >= n || j + 1 >= m) {
            flag = 0;
          } else {
            int d = b[i][j] - a[i][j];
            a[i][j] = (a[i][j] + d + 3) % 3; 
            a[i + 1][j + 1] = (a[i + 1][j + 1] + d + 3) % 3;
            a[i + 1][j] = (a[i + 1][j] + 3 - d) % 3; 
            a[i][j + 1] = (a[i][j + 1] + 3 - d) % 3;
          }
        }
      }
    }

    std::cout << (flag ? "YES" : "NO") << "\n";
  }
  return 0;
}

C

枚举。

套路题,首先 3! 地枚举三个人获得的段的顺序。所有数均大于零,则第一个人一定获得一段前缀,第三个人一定获得一段后缀,第二个人取中间所有的数。考虑枚举第一个人获得的前缀,在令其不小于 \(L = \left\fceil\frac{tot}{3}\right\rceil\) 的基础上,二分得到最短的第三个获得的后缀使其不小于 \(L\),再检查中间一段是否不大于 \(L\) 即可。

复杂度 \(O(n\log n)\) 级别。

可以双指针枚举中间一段做到 \(O(n)\)。

写挺丑。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN], b[kN], c[kN], ans[7];
LL prea[kN], preb[kN],  sufc[kN];
LL tot, lim;
//=============================================================
bool solve(std::vector<int> &a_, std::vector<int> &b_, std::vector<int> &c_) {
    for (int i = 1; i <= n; ++ i) prea[i] = prea[i - 1] + a_[i - 1];
    for (int i = 1; i <= n; ++ i) preb[i] = preb[i - 1] + b_[i - 1];
    sufc[n + 1] = 0;
    for (int i = n; i; -- i) sufc[i] = sufc[i + 1] + c_[i - 1];

    for (int i = 1; i <= n; ++ i) {
      if (prea[i] < lim) continue;
      int l = i + 2, r = n, p = -1;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (preb[mid - 1] - preb[i] < lim) {
          l = mid + 1;
        } else {
          p = mid;
          r = mid - 1;
        }
      }
      if (p == -1) continue;
      if (sufc[p] < lim) continue;

      ans[1] = 1, ans[2] = i;
      ans[3] = i + 1, ans[4] = p - 1;
      ans[5] = p, ans[6] = n;
      return true;
    }
    return false;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n;
    std::vector<int> aa, bb, cc;
    tot = lim = 0;
    for (int i = 1; i <= n; ++ i) {
      std::cin >> a[i];
      aa.push_back(a[i]);
      tot += a[i];
    }
    lim = 1ll * ceil(tot / 3.0);
    for (int i = 1; i <= n; ++ i) {
      std::cin >> b[i];
      bb.push_back(b[i]);
    }
    for (int i = 1; i <= n; ++ i) {
      std::cin >> c[i];
      cc.push_back(c[i]);
    }

    if (solve(aa, bb, cc)) {
      std::cout << ans[1] << " " << ans[2] << " ";
      std::cout << ans[3] << " " << ans[4] << " ";
      std::cout << ans[5] << " " << ans[6] << " " << "\n";
    } else if (solve(aa, cc, bb)) {
      std::cout << ans[1] << " " << ans[2] << " ";
      std::cout << ans[5] << " " << ans[6] << " ";
      std::cout << ans[3] << " " << ans[4] << " " << "\n";
    } else if (solve(bb, aa, cc)) {
      std::cout << ans[3] << " " << ans[4] << " ";
      std::cout << ans[1] << " " << ans[2] << " ";
      std::cout << ans[5] << " " << ans[6] << " " << "\n";
    } else if (solve(bb, cc, aa)) {
      std::cout << ans[5] << " " << ans[6] << " ";
      std::cout << ans[1] << " " << ans[2] << " ";
      std::cout << ans[3] << " " << ans[4] << " " << "\n";
    } else if (solve(cc, aa, bb)) {
      std::cout << ans[3] << " " << ans[4] << " ";
      std::cout << ans[5] << " " << ans[6] << " ";
      std::cout << ans[1] << " " << ans[2] << " " << "\n";
    } else if (solve(cc, bb, aa)) {
      std::cout << ans[5] << " " << ans[6] << " ";
      std::cout << ans[3] << " " << ans[4] << " ";
      std::cout << ans[1] << " " << ans[2] << " " << "\n";
    } else {
      std::cout << -1 << "\n";
    }
  }
  return 0;
}

D

结论,逆序对。

先判断两数列中各元素数量是否相同。

发现若存在方案使得两数列相同,则在此之后可任意操作使两数列相同前提下任意排列。一个显然的想法是使两数列均变为有序状态;又发现一次交换操作可以转换为若干次相邻的两个数交换,相邻两个数交换的结果是逆序对数加减 1,可以发现两数列能均变为有序状态的充要条件,是两数列的逆序对的奇偶性相同。

于是仅需分别求逆序对即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const int kLim = 2e5;
//=============================================================
int n, a[kN], b[kN];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0'); 
  return f * w;
}
namespace BIT {
  #define lowbit(x) ((x)&(-x))
  const int kL = kN;
  int lim, nowtime, tag[kN];
  LL f[kN];
  void Init(int n_) {
    ++ nowtime;
    lim = n_;
  }
  void Insert(int pos_, int val_) {
    for (int i = pos_; i <= lim; i += lowbit(i)) {
      if (tag[i] != nowtime) f[i] = 0, tag[i] = nowtime;
      f[i] += val_;
    }
  }
  LL Sum(int pos_) {
    LL ret = 0;
    for (int i = pos_; i; i -= lowbit(i)) {
      if (tag[i] != nowtime) f[i] = 0, tag[i] = nowtime;
      ret += f[i];
    }
    return ret;
  }
  LL Query(int l_, int r_ = lim) {
    return Sum(r_) - Sum(l_ - 1);
  }
  #undef lowbit
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  int T = read();
  while (T --) {
    n = read();
    LL s1 = 0, s2 = 0;
    BIT::Init(kLim);
    for (int i = 1; i <= n; ++ i) {
      a[i] = read();
      BIT::Insert(a[i], 1);
      s1 += BIT::Query(a[i] + 1);
    }
    BIT::Init(kLim);
    for (int i = 1; i <= n; ++ i) {
      b[i] = read();
      BIT::Insert(b[i], 1);
      s2 += BIT::Query(b[i] + 1);
    }
    std::sort(a + 1, a + n + 1);
    std::sort(b + 1, b + n + 1);
    
    int flag = 1; 
    for (int i = 1; i <= n; ++ i) {
      if (a[i] != b[i]) {
        flag = 0;
        break;
      }
    }
    if (flag && s1 % 2 == s2 % 2) std::cout << "YES\n";
    else std::cout << "NO\n";
  }
  return 0;
}

E

期望,组合数

因为是期望,于是仅需考虑两种球的期望获得个数,再分别乘上其平均价值即可。

一个显然的想法是考虑构造两个人按顺序拿球构成的排列。拿到普通球后换人,一个显然的想法是以普通球为间隔进行分段,然后在各段里插入特别球表示可连续获得的数量来构造。根据奇偶性即可得到每段分别属于哪个人。

在上述构造中,先手拿到的普通球期望数量显然为:

\[\left\lceil\frac{n - k}{2}\right\rceil \]

共有 \(n - k + 1\) 段,先手会拿走其中 \(\left\lceil\frac{n - k + 1}{2}\right\rceil\) 段,而每个特殊球在每段中出现概率相同,则先手拿到的特殊球期望数量为:

\[\frac{k}{n - k + 1}\times \left\lceil\frac{n - k + 1}{2}\right\rceil \]

上述两个数量分别乘上平均价值即为先手的期望得分。后手得分即为总价值和减去先手期望得分。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const LL p = 1e9 + 7;
//=============================================================
//=============================================================
LL qpow(LL x_, LL y_) {
  LL ret = 1;
  while (y_) {
    if (y_ & 1ll) ret = ret * x_ % p;
    x_ = x_ * x_ % p, y_ >>= 1ll;
  }
  return ret;
}
LL inv(LL x_) {
  return qpow(x_, p - 2);
}
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    LL n, k, s1 = 0, s2 = 0;
    std::cin >> n >> k;
    for (int i = 1; i <= n; ++ i) {
      int x; std::cin >> x;
      if (i <= k) s1 += x, s1 %= p;
      else s2 += x, s2 %= p;
    }
    LL ans = 1ll * (n - k + 1) / 2ll * s2 % p * inv(n - k) % p;
    ans += 1ll * (n - k + 2) / 2ll * k % p * inv(n - k + 1) % p * s1 % p * inv(k) % p;
    ans %= p;

    std::cout << ans << " " << (s1 + s2 - ans + p) % p << "\n";
  }
  return 0;
}

F

01 Trie,贪心,二分答案

这题好几把眼熟——你是否在找 「十二省联考 2019」异或粽子 的另一数据范围版本 CF241B Friends

和 CF241B 类似地,考虑二分答案 \(\operatorname{lim}\),仅需检查是否有小于 \(k\) 个区间的价值小于 \(\operatorname{lim}\) 即可。

考虑枚举区间的右端点 \(r\),并检查区间 \([1, r] \sim [r, r]\) 中有多少有贡献。一个显然的想法是对 \(a_1\sim a_{r - 1}\) 维护一棵 01 Trie,然后用 \(a_r\) 在上面贪心地逐位匹配令 \(a_l \oplus a_r\) 小于 \(\operatorname{lim}\) 即可,求得有哪些 \(l\) 可令 \(a_l \oplus a_r\) 的价值小于 \(\operatorname{lim}\)。记其中最大的为 \(L_r\),则根据区间价值的定义,有贡献的区间左端点为:

\[1\sim \max_{1\le i\le r} L_i \]

在上述过程中对有贡献的区间左端点计数即可完成检查。Trie 单次插入和贪心匹配均为 \(O(\log v)\) 级别,则总时间复杂度 \(O(n\log^2 v)\) 级别。

注意多次检查时 Trie 要懒惰清空,清空时注意必须将左右儿子也清空。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e5 + 10;
//=============================================================
int n;
LL k, a[kN], ans;
//=============================================================
namespace Trie {
  const int kNode = kN << 5;
  int nodenum, nowtime, tr[kNode][2], tag[kNode], id[kNode];
  void init() {
    ++ nowtime;
    nodenum = 0;
  }
  void insert(LL val_, int id_) {
    int now_ = 0;
    for (LL i = 30; i >= 0; -- i) {
      LL ch = val_ >> i & 1ll;
      if (!tr[now_][ch] || tag[tr[now_][ch]] != nowtime) {
        tr[now_][ch] = ++ nodenum;
        tr[nodenum][0] = tr[nodenum][1] = 0;
      }
      now_ = tr[now_][ch];
      tag[now_] = nowtime;
      id[now_] = id_;
    }
  }
  int query(LL val_, LL lim_) {
    int now_ = 0, ret = 0;
    for (LL i = 30; i >= 0; -- i) {
      LL ch1 = val_ >> i & 1ll, ch2 = lim_ >> i & 1ll;

      if (ch2 == 1 && tr[now_][ch1] && tag[tr[now_][ch1]] == nowtime) {
        ret = std::max(ret, id[tr[now_][ch1]]);
      }
      if (tr[now_][ch1 ^ ch2] && tag[tr[now_][ch1 ^ ch2]] == nowtime) {
        now_ = tr[now_][ch1 ^ ch2];
      } else {
        break;
      }
    }
    return ret;
  }
}
bool check(int lim_) {
  LL maxp = 0, sum = 0;
  Trie::init(), Trie::insert(a[1], 1);
  for (int i = 2; i <= n; ++ i) {
    maxp = std::max(maxp, 1ll * Trie::query(a[i], lim_));
    sum += maxp;
    Trie::insert(a[i], i);
  }
  return sum < k;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    std::cin >> n >> k;
    for (int i = 1; i <= n; ++ i) std::cin >> a[i];
    for (LL l = 0, r = 2e9; l <= r; ) {
      LL mid = (l + r) >> 1ll;
      if (check(mid)) {
        ans = mid;
        l = mid + 1;
      } else {
        r = mid - 1;
      }
    }
    std::cout << ans << "\n";
  }
  return 0;
}

写在最后

参考:

因为国服一周年了所以放一个 PV 在这里。PV 做得很有感觉啊但是歌和日服广播剧的 La La Run 还是有一定差距呃呃、、、

<iframe allowfullscreen="allowfullscreen" frameborder="0" height="500" sandbox="allow-top-navigation allow-same-origin allow-forms allow-scripts" scrolling="no" src="//player.bilibili.com/player.html?aid=1803319537&bvid=BV1v4421D76V&cid=1514945472&p=1" width="100%"> </iframe>

标签:std,kN,int,cin,LL,Codeforces,956,2024,now
From: https://www.cnblogs.com/luckyblock/p/18303811

相关文章

  • P10720 [GESP202406 五级] 小杨的幸运数字 题解
    题意如果一个数的质因子中只有两个不同的数则输出\(1\),否则输出\(0\)。思路从第一个质因子遍历到\(sum\)的话很明显是\(O(nt)\)最大是\(n^{10}\)很明显会炸掉。所以遍历到\(sum\)是不行的,考虑正整数\(n\)最大的质因数是\(\sqrt{n}\)所以遍历到\(\sqrt{n}\)即......
  • JavaAPI练习(1) (2024.7.15)
        Math类packageMathExercise20240715;//Math类所在的是java.lang包,属于核心包,无需导包publicclassMathExercise{publicstaticvoidmain(String[]args){//Math方法为静态的,不需要创建对象,直接类名调用即可//abs返回参数的绝对......
  • 7.15鲜花——2024dl24灯光秀游记
    前言时光的背面有阑珊灯火那红墙绿树由我们诠说不问从前烟火无惧前路宕落我们将扬帆向未来漂泊就算在背对阳光的角落那不凡荣光把我们包裹每一个山长水阔每一条寻常巷陌每一颗心都依然灼热同灯火唱和少年翘首以盼的天晴等来属于盛夏的蜩鸣那些黑板书写的叮咛成了谁的曾经时光的......
  • 2024-07-15 vue组件发布npm后,再使用,样式不见了?==》查看样式是否在dist包里,有的话应
    哎,嗯。。。emmm。。。好,问题就是这样的,最近写了vue组件打算上到npm,然后上是上了,但是样式却没有生效??左上角是组件样式本地调试的截图,可以看到是生效的,右上角的截图是我在别的项目引用了我写的这个库,结果样式却没有生效。我打包后的文件列表如下: 注意:style.css包含了所有的样......
  • 云原生周刊:Score 成为 CNCF 沙箱项目|2024.7.15
    开源项目TridentTrident是由NetApp维护的全面支持的开源项目。它从头开始设计,旨在通过行业标准接口(如容器存储接口CSI)帮助您满足容器化应用程序对持久性存储的需求。MonokleMonokle通过提供用于编写YAML清单、验证策略和管理实时集群的统一可视化工具,简化了创建、分析......
  • 2024-07-15 记录一则vue网站优化的小技巧
    vite+vue+某框架写的网站可以通过配置vite.config.js中的build.rollupOptions.output.manualChunks来手动分割指定的包到指定的文件夹内,然后在网站入口文件按照需求引入比如:build:{rollupOptions:{output:{manualChunks:{antd......
  • 2024年职业院校大数据实验室建设及大数据实训平台整体解决方案
    随着大数据技术的飞速发展,职业院校的大数据实验室建设与实训平台的打造成为教育领域关注的焦点。为了培养适应时代需求的专业人才,2024年的职业院校大数据实验室建设将遵循以下原则与策略:首要任务是明确实验室建设的学科定位,结合学校特色与行业优势,制定人才培养目标。这要求我......
  • 2024年中职人工智能实验室建设及人工智能实训平台整体解决方案
    随着人工智能技术的日益成熟与广泛应用,中等职业教育在培养未来技能型人才方面扮演着越来越重要的角色。为了响应时代需求,提升中职学生在人工智能领域的专业素养与实践能力,特制定《2024年中职人工智能实验室建设及人工智能实训平台整体解决方案》。1、中职人工智能实验室的建设......
  • WAIC 2024盛大召开,天翼云以全栈智算能力赋能AI时代!
     7月5日,2024世界人工智能大会期间,中国电信星辰人工智能生态论坛在上海世博中心启幕。论坛以“星辰注智,焕新领航”为主题,围绕人工智能技术发展趋势,分享中国电信与产业各界在人工智能领域的创新与实践。天翼云科技有限公司董事长、总经理胡志强出席,并发表演讲《云智一体国云焕新......
  • WAIC 2024,好city啊!
    7月4日,“以共商促共享•以善治促善智”为主题的2024世界人工智能大会暨人工智能全球治理高/级别会议(简称“WAIC2024”)在上海举办。天翼云携智算创新成果精彩亮相世博展览馆,全方位展现在人工智能领域的深厚实力。 智算领航,引领科技新方向AI时代,“云智一体”已成为行业共识,在“......