首页 > 其他分享 >Codeforces Round 932 (Div. 2)

Codeforces Round 932 (Div. 2)

时间:2024-03-07 22:56:18浏览次数:30  
标签:std cnt int Codeforces kN ans 932 Div operatorname

目录

写在前面

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

被精心构造的 C 的样例鲨了的一集。

妈的天使骚骚☆REBOOT完全就是他妈拔作啊我草,要是被人知道我他妈推了全线要被笑话一辈子吧、、、

A

签到。

操作偶数次,则答案仅可能为 sreverse(s) + s,更长的字符串的前缀一定为二者之一,则选择这两者是最优的。

则仅需比较 sreverse(s) 的字典序即可。

//
/*
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;
    std::string s; std::cin >> s;
    std::string t = s; std::reverse(t.begin(), t.end()); 
    if (s <= t) std::cout << s << "\n";
    else std::cout << t + s << "\n";
  }
  return 0;
}

B

枚举。

显然答案仅可能为 \(\operatorname{mex}_{i=1}^{n} a_i\) 或无解。

于是检查 \(\operatorname{mex}_{i=1}^{n} a_i\) 是否可以成为答案。发现若可以分成多段,则一定可以分成两段,于是仅需枚举两段互补的前缀后缀并检查它们的 \(\operatorname{mex}\) 是否为 \(\operatorname{mex}_{i=1}^{n} a_i\) 即可。

赛时写的比较傻比,先找到了最短的满足 \(\operatorname{mex} = \operatorname{mex}_{i=1}^{n} a_i\) 的前缀,然后再检查剩下的后缀是否也满足条件。

//枚举
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e5 + 10;
//=============================================================
int n, ans, a[kN];
bool yes[kN];
std::vector <std::pair <int, int> > sol;

int cntnum, nowtime, cnt[kN], tim[kN];
//=============================================================
void add(int x_) {
  if (tim[x_] != nowtime) cnt[x_] = 0, tim[x_] = nowtime;
  if (!cnt[x_]) ++ cntnum;
  ++ cnt[x_];
}
void clear() {
  cntnum = 0;
  ++ nowtime;
}
void check(int mex_) {
  int sum = 0, last = 1;
  sol.clear();
  for (int i = 1; i <= n; ++ i) {
    if (a[i] < mex_) add(a[i]);
    if (cntnum == mex_) {
      ++ sum; 
      clear();
      if (sol.empty()) sol.push_back(std::make_pair(last, i)), last = i + 1;
    }
  }
  
  sol.push_back(std::make_pair(last, n));
  if (sum >= 2) ans = mex_;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;

  
  while (T --) {
    ans = -1;
    sol.clear();
    clear();

    std::cin >> n;
    for (int i = 0; i <= n; ++ i) yes[i] = 0;
    for (int i = 1; i <= n; ++ i) {
      std::cin >> a[i];
      yes[a[i]] = 1;
    }
    
    for (int i = 0; i <= n; ++ i) {
      if (!yes[i]) {
        check(i);
        break;
      }
    }
    if (ans == -1) {
      std::cout << -1 << "\n";
      continue;
    }
    std::cout << sol.size() << "\n";
    for (auto x: sol) 
      std::cout << x.first << " " << x.second << "\n";
  }
  return 0;
}

C

枚举,排序,线段树

被精心构造的 C 的样例鲨了的一集。

这个贡献的形式显然是典中典,考虑将所有元素按 \(b\) 排序然后枚举区间 \([l, r]\) 表示钦定选择了元素 \(l, r\),使选择的元素满足后半部分贡献为 \(b_{r} - b_{l}\),之后应在 \((l, r)\) 中再选择尽可能多的元素使总贡献不超过 \(T\),此时仅需考虑 \(a\) 的贡献即可。

显然应当按照 \(a\) 升序选择元素,一个显然的想法是用线段树维护 \((l, r)\) 中元素的属性 \(a\),以 \(a\) 的值为下标维护区间元素个数与区间贡献之和,然后在线段树上以上限 \(T - (b_r - b_l) - (a_r + a_l)\) 二分即可得到至多能选择元素的数量。

在枚举区间的同时维护线段树即可。注意对 \(a\) 先离散化,总时间复杂度 \(O(\sum n^2\log n)\) 级别。

有复杂度同阶的 DP 解法。

为什么想到这个?因为前天刚写了一个线段树上二分的题,直接复制过来用了哈哈

//枚举,排序,线段树
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
#define pii std::pair<int,int>
#define mp std::make_pair
const int kN = 2010;
//=============================================================
int n, datanum, b[kN];
pii a[kN];
LL ans, l;
//=============================================================
namespace Seg {
  #define ls (now_<<1)
  #define rs (now_<<1|1)
  #define mid ((L_+R_)>>1)
  const int kNode = kN << 2;
  LL sum[kNode], cnt[kNode];
  void Pushup(int now_) {
    sum[now_] = sum[ls] + sum[rs];
    cnt[now_] = cnt[ls] + cnt[rs];
  }
  void Insert(int now_, int L_, int R_, int pos_, LL sum_, LL cnt_) {
    if (L_ == R_) {
      sum[now_] += sum_;
      cnt[now_] += cnt_;
      return ;
    }
    if (pos_ <= mid) Insert(ls, L_, mid, pos_, sum_, cnt_);
    else Insert(rs, mid + 1, R_, pos_, sum_, cnt_);
    Pushup(now_);
  }
  LL Query(int now_, int L_, int R_, LL lim_) {
    if (L_ == R_) {
      return std::min(cnt[now_], lim_ / b[L_]);
    }
    LL sl = sum[ls], cl = cnt[ls];
    if (lim_ <= sl) return Query(ls, L_, mid, lim_);
    return cl + Query(rs, mid + 1, R_, lim_ - sl);
  }
  #undef ls
  #undef rs
  #undef mid
}
void Solve() {
  ans = 0;

  for (int i = 1; i <= n; ++ i) {
    for (int j = i; j <= n; ++ j) {
      LL cost = 1ll * b[a[i].second] + 1ll * (j > i) * b[a[j].second] + a[j].first - a[i].first;
      if (l >= cost) {
        LL c = 1 + (j > i) + Seg::Query(1, 1, datanum, l - cost);
        ans = std::max(ans, c);
      }
      if (j > i) Seg::Insert(1, 1, datanum, a[j].second, b[a[j].second], 1);
    }
    for (int j = i; j <= n; ++ j) {
      if (j > i) Seg::Insert(1, 1, datanum, a[j].second, -b[a[j].second], -1);
    }
  }
}
void Init() {
  ans = 0;
  std::cin >> n >> l;
  for (int i = 1; i <= n; ++ i) {
    int x, y; std::cin >> x >> y;
    a[i] = mp(y, x);
  }
  std::sort(a + 1, a + n + 1);
  for (int i = 1; i <= n; ++ i) b[i] = a[i].second;

  std::sort(b + 1, b + n + 1);
  datanum = std::unique(b + 1, b + n + 1) - b - 1;
  for (int i = 1; i <= n; ++ i) {
    a[i].second = std::lower_bound(b + 1, b + datanum + 1, a[i].second) - b; 
  }
}

//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    Init();
    Solve();
    std::cout << ans << "\n";
  }
  return 0;
}
/*
1
5 100
1 1
1000 2
1000 3
1000 4
1 98
*/

D

数学,容斥

一眼题。C 实在调不出来看了一眼就会的呃呃题,五分钟过了之后继续调 C 呃呃

考虑求补集,即求多少二元组 \((x, y)(x\le y)\) 满足 \((x + y\in \{s_i\})\lor (y - x\in \{s_i\})\)。保证了 \(s_i\) 两两不同,则简单容斥下即求下列三部分二元组的数量:

  • \(f_1: (x + y \in \{s_i\})\),数量为 \(\sum_i \left\lfloor\frac{s_i}{2}\right\rfloor + 1\)。
  • \(f_2: (y - x\in \{s_i\})\),数量为 \(\sum_i c - s_i + 1\)。
  • \(f_3: (x + y\in \{s_i\}) \land (y - x\in \{s_j\})\),若二元组满足该条件,则有 \(i\not= j\) 且 \(s_i \equiv s_j \pmod 2\),则记 \(s_i\bmod 2 = 0/1\) 的数量分别为 \(k_0, k_1\),二元组数量为 \(\frac{k_0(k_0 + 1)}{2} + \frac{k_1(k_1 + 1)}{2}\)。

答案即为 \(\frac{c(c + 1)}{2} - f_0 - f_1 + f_2\),复杂度 \(O\left(\sum n\right)\) 级别。

//数学,容斥
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 3e5 + 10;
//=============================================================
int n, c, s[kN];
LL ans;
//=============================================================
void Solve() {
  ans = 1ll * (c + 1) * (c + 2) / 2ll;

  int cnt[2] = {0, 0};
  for (int i = 1; i <= n; ++ i) {
    ans -= s[i] / 2ll + 1;
    ans -= c - s[i] + 1;

    ++ cnt[s[i] % 2];
  }
  ans += 1ll * cnt[0] * (cnt[0] + 1ll) / 2ll;
  ans += 1ll * cnt[1] * (cnt[1] + 1ll) / 2ll;
}
//=============================================================
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 >> c;
    for (int i = 1; i <= n; ++ i) std::cin >> s[i];
    Solve();
    std::cout << ans << "\n";
  }
  return 0;
}

E

位运算,贪心,线段树

好玩的按位或。

先考虑 \(\forall 1\le i\le n,\ x_i = 0\) 的情况,考虑按位贪心。设当前降序枚举到 \(i(0\le i\le 29)\) 位,记 \(c_i\) 表示 \([l, r]\) 内有多少元素的 \(y\) 此位为 1:

  • \(c_i = 0\):则此位无贡献。
  • \(c_i = 1\):贡献为 \(2^{i}\),来自唯一的此位为 1 的数。
  • \(c_i\ge 2\):贡献为 \(2^{i} + (2^{i} - 1)\),令 \(y\) 此位为 1 的两个元素一个取 \(y\),一个取 \((y - 2^i) \operatorname{or} (2^{i} - 1)\) 即可,则之后所有位均有贡献,直接停止枚举即可。

当 \(x\not= 0\) 时类似,同样考虑按位贪心并考虑每位为 1 的有多少个数。\(c_i=0/1\) 的情况不受影响,然而对于 \(c_i\) 可能有 \(2^{i}-1< x\),使对应元素无法取到 \(2^i - 1\) 影响 \(c_i\ge 2\) 的贡献。但想法还是相同的:对于 \(c_i\ge 2\) 的位,仅取其中一个保留第 \(i\) 位贡献,其他数向下调整使得某位 \(j\) 之后的所有位均有贡献。

手玩下发现满足条件的最大的 \(j\) 即为 \(x, y\) 中按照降序第一位不同的,由于 \(y>x\) 则一定有 \(y\) 第 \(j\) 位为 1,\(x\) 第 \(j\) 位为 0,则此时该元素可取到 \((y - 2^j) \operatorname{or} (2^j - 1) \ge x\),使 \(j\) 位之后的贡献均为 1——感觉和特殊情况很类似?

于是考虑先预处理出每个元素的 \(x, y\) 中按照降序第一位不同的位 \(j\),发现每个元素 \(j\) 位之前的部分一定可以贡献到答案中,于是先将这部分提取出来线段树维护区间按位或;对于 \(j\) 位及之后的部分 \(y\operatorname{and} (2^{j+1} - 1)\),此时相当于 \(x'=0, y' = y\operatorname{and} (2^{j+1} - 1)\) 的对 \(x'\) 无限制的情况,可以套用一开始的特殊情况。

总时间复杂度 \(O\left((n + m)\left(\log n + \log v\right)\right)\) 级别。

//位运算,贪心,线段树
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, m, must[kN], cnt[31][kN];
//=============================================================
namespace Seg {
  #define ls (now_<<1)
  #define rs (now_<<1|1)
  #define mid ((L_+R_)>>1)
  const int kNode = kN << 2;
  int t[kNode];
  void Pushup(int now_) {
    t[now_] = t[ls] | t[rs];
  }
  void Build(int now_, int L_, int R_) {
    if (L_ == R_) {
      t[now_] = must[L_];
      return ;
    }
    Build(ls, L_, mid), Build(rs, mid + 1, R_);
    Pushup(now_);
  }
  int Query(int now_, int L_, int R_, int l_, int r_) {
    if (l_ <= L_ && R_ <= r_) return t[now_];
    int ret = 0;
    if (l_ <= mid) ret |= Query(ls, L_, mid, l_, r_);
    if (r_ > mid) ret |= Query(rs, mid + 1, R_, l_, r_);
    return ret;
  }
  #undef ls
  #undef rs
  #undef mid
}
void Init() {
  std::cin >> n;
  for (int i = 1; i <= n; ++ i) {
    int x, y; std::cin >> x >> y;
    for (int j = 29; j >= 0; -- j) {
        cnt[j][i] = cnt[j][i - 1];
      }
    if (x == y) {
      must[i] = x;
    } else {
      int val = (1 << ((int) log2(x ^ y) + 1)) - 1;
      must[i] = y - (y & val);
      val = y & val;
      for (int j = 29; j >= 0; -- j) {
        cnt[j][i] += ((val >> j & 1) > 0);
      }
    }
  }
  Seg::Build(1, 1, n);
}
int Query(int l_, int r_) {
  int ans = Seg::Query(1, 1, n, l_, r_);
  for (int i = 29; i >= 0; -- i) {
    int c = cnt[i][r_] - cnt[i][l_ - 1] + (ans >> i & 1);
    if (c > 1) {
      ans |= (1 << (i + 1)) - 1; 
    } else if (c == 1) {
      ans |= (1 << i);
    }
  }
  return ans;
}
//=============================================================
int main() {
  //freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    Init();

    for (int i = 1; i <= n; ++ i) std::cout << must[i] << "\n";

    std::cin >> m;
    while (m --) {
      int l_, r_; std::cin >> l_ >> r_;
      std::cout << Query(l_, r_) << " ";
    }
    std::cout << "\n";
  }
  return 0;
}
/*
1
1
2 2
1
1 1
*/

写在最后

学到了什么:

  • B:区间 $\operatorname{mex}\le $ 全局 \(\operatorname{mex}\)。
  • E:提取贡献,转化为特殊情况。

标签:std,cnt,int,Codeforces,kN,ans,932,Div,operatorname
From: https://www.cnblogs.com/luckyblock/p/18059970

相关文章

  • CF contest 1935 Round 932 (Div. 2) A-D题解
    CodeforcesRound932(Div.2)A-D题解CodeforcesRound932(Div.2)绪言很菜,AB速度慢,卡在C,想DP,但是时间优化不下来,说服自己\(2\times10^3\)能过\(n^3\),D稍微简单,但是没看D,遂掉分。A.EntertainmentinMAC给你一个字符串\(s\)和一个偶整数\(n\)。你可以对它进行两种运......
  • Codeforces 专区
    CodeforcesRound#932(Div.2)怎么只会A啊。\(\text{ProblemA}\)题目大意对于一个字符串\(s\),可以进行\(n\)次操作(\(n\)为偶数),每次操作有两种形式:令\(t\)为\(s\)的反串,\(s=s+t\)。令\(t\)为\(s\)的反串,\(s=t\)。要求操作完后\(s\)的字典序最小,并输......
  • Though Our Paths May Diverge(JSOI 2024 游记)
    Isn’titsupposedtobesunnynow?且当是JSOI2024的游记吧。省选前的精神状态处于一种微妙的平衡。确实也不断在给自己心理暗示,自己有省队水平,但是其实无论是哪边的模拟打得都属于比较稀烂的水平,有的时候真的是一题不会签不上到。跟不上zhy和黄色蜜蜂的节奏啊,大概就......
  • CF-932(已更新 A B)
    CF-932(已更新AB)之前的CF也都掉分了的打了的,只是都还没补题……逆天舍友打游戏看抖音都外放-^-,打游戏生气了还要大声地祖安别人……A赛时只想到了在暴力的做法,写得还巨丑,鉴定为天天喝八宝粥喝的(⊙﹏⊙)分析题意已经如此直白而自己赛时居然一直在死磕一个最复杂的写法......
  • Codeforces Round 931div2补题
    B.YetAnotherCoinProblem真[https://www.bilibili.com/video/BV1o2421M7pV/]不同硬币之间有倍数关系,使得一定数量后的小硬币可以被大硬币替代达到最优方案,而每个小硬币在最优下有可能的数量如下,进行枚举后找到最优方案。1:不多于2个(3个1会被3替代)3:不多于一个(2个3......
  • 并查集解mex_cf932_B. Informatics in MAC
    目录题目概述思路想法参考代码做题反思题目概述原题参考:B.InformaticsinMAC给出一个长度为n的数组,问是否可以将其分为k个(k>1)mex相同的数组,如果可以的话,作出一种划分思路想法假设一个数组可以被分为k(k>2)个区间,每个区间的mex相同,那么可以确定的是,该数组中一定不存在mex这......
  • 1935.Codeforces Round 932 (Div. 2) - sol
    20240306逊哎~打一半去写申请书然后12点睡觉,相对成功!第二天早上起来把赛时发愣的C和F切了。CodeforcesRound932(Div.2)A.EntertainmentinMACCongratulations,youhavebeenacceptedtotheMaster'sAssistanceCenter!However,youwereextremelybore......
  • Codeforces Round 932 (Div. 2)
    CodeforcesRound932(Div.2)A-EntertainmentinMAC解题思路:如果翻转字符小于原字符,那么一直翻转即可。否则,翻转\(n-1\)次,然后添加一次。代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;usingpii=pair<ll,ll>;typedefdoubledb;......
  • div contenteditable="true" 添加placehoder效果
    <divclass="contain":style="{height:editableHeight+'px'}" v-html="innerText" ref="editableDiv" contenteditable="true" :placeholder=placeholder @input="inputTe......
  • css div 三张背景图片
    cssdiv宽度1300高度46,同时给它设置三张背景图片堆叠同时显示,其一图片宽度1300高度46,铺满整个div且距离最左侧偏移22px,其二图片宽度44,高度43,在div的最左端,其三图片宽度83,高度43,在div的最右端,他们同时垂直居中在div中  .container{width:1300px;height:4......