首页 > 其他分享 >CF1408H Rainbow Triples 题解

CF1408H Rainbow Triples 题解

时间:2024-02-28 21:02:51浏览次数:28  
标签:std Rainbow right Triples int 题解 lfloor rfloor vec

Description

给定长度为 \(n\) 的序列 \(p\)

找出尽可能多的三元组 \((a_i,b_i,c_i)\) 满足:

  • \(1\le a_i<b_i<c_i\le n\)
  • \(p_{a_i}=p_{c_i}=0\),\(p_{b_i}\ne 0\)
  • \(p_{b_i}\) 互不相同。
  • 所有的 \(a_i,b_i,c_i\) 互不相同。

输出最多可以选出多少个三元组,多组数据。

\(\sum n\le 5\cdot 10^5\)

Solution

设总共有 \(c\) 个 \(0\),容易发现答案的上界是 \(\left\lfloor\frac{c}{2}\right\rfloor\),并且对于每个三元组,\(a_i\) 一定在前 \(\left\lfloor\frac{c}{2}\right\rfloor\) 个,\(c_i\) 一定在最后 \(\left\lfloor\frac{c}{2}\right\rfloor\) 个。

因为如果不满足那么调整成这个情况一定更优。

然后考虑一个 \(b_i\),如果在前 \(\left\lfloor\frac{c}{2}\right\rfloor\) 个 \(0\) 的区间里,那么如果它能够与 \(\left\lfloor\frac{c}{2}\right\rfloor\) 匹配那么一定能和右边的 \(0\) 匹配,如果在右边则一定能与左边的 \(0\) 匹配。

所以只要把 \(mid\) 左边和右边的分开考虑然后把答案相加与 \(\left\lfloor\frac{c}{2}\right\rfloor\) 取 min。

容易发现对于一个颜色,只有 \(<mid\) 的最大位置和 \(>mid\) 的最小位置有意义,所以把这个颜色与 \(<mid\) 的位置之前的 \(0\) 和 \(>mid\) 的位置之后的 \(0\) 连边跑网络流即可,显然过不了。

注意到一个颜色匹配的一定是一个前缀+一个后缀,所以把 \(mid\) 之前的 \(0\) 移到最后面,那么每个颜色匹配的就是一个区间 \([l,r]\),于是只要先按 \(r\) 排序然后贪心即可。

时间复杂度:\(O(n\log n)\)。

Code

#include <bits/stdc++.h>
 
// #define int int64_t
 
const int kMaxN = 5e5 + 5;
 
int n;
int a[kMaxN];
std::vector<int> vec[kMaxN];
 
void dickdreamer() {
  std::cin >> n;
  for (int i = 0; i <= n; ++i) vec[i].clear();
  for (int i = 1; i <= n; ++i) {
    std::cin >> a[i];
    vec[a[i]].emplace_back(i);
  }
  // if (vec[0].size() & 1) vec[0].erase(vec[0].begin() + vec[0].size() / 2);
  if (!vec[0].size()) return void(std::cout << "0\n");
  int cnt = vec[0].size(), L, R;
  if (vec[0].size() & 1) L = R = vec[0][(vec[0].size() - 1) / 2];
  else L = vec[0][vec[0].size() / 2 - 1], R = vec[0][vec[0].size() / 2];
  std::vector<std::pair<int, int>> rg;
  for (int i = 1; i <= n; ++i) {
    if (!vec[i].size()) continue;
    int id1 = -1, id2 = n + 1;
    for (auto x : vec[i]) {
      if (x < R) id1 = x;
      if (x > L && id2 == n + 1) id2 = x;
    }
    id1 = std::lower_bound(vec[0].begin(), vec[0].end(), id1) - vec[0].begin() - 1;
    id2 = std::lower_bound(vec[0].begin(), vec[0].end(), id2) - vec[0].begin();
    rg.emplace_back(id2, cnt + id1);
  }
  auto cmp = [](const std::pair<int, int> &p1, const std::pair<int, int> &p2) {
    return std::make_pair(p1.second, p1.first) < std::make_pair(p2.second, p2.first);
  };
  std::sort(rg.begin(), rg.end(), cmp);
  std::set<int> st;
  for (int i = 0; i < 2 * cnt; ++i) st.emplace(i);
  int ans = 0;
  for (auto p : rg) {
    auto it = st.lower_bound(p.first);
    if (it != st.end() && *it <= p.second) ++ans, st.erase(it);
  }
  std::cout << std::min(ans, cnt / 2) << '\n';
}
 
int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:std,Rainbow,right,Triples,int,题解,lfloor,rfloor,vec
From: https://www.cnblogs.com/Scarab/p/18041771

相关文章

  • P10160 [DTCPC 2024] Ultra 题解
    【题目描述】给你一个\(01\)序列,你可以进行如下操作若干次(或零次):将序列中形如\(101\cdots01\)的一个子串(即\(1(01)^k\),\(k\ge1\))替换成等长的\(010\cdots10\)(即\(0(10)^k\))。你要操作使得\(1\)的个数尽可能少,输出最少的\(1\)的个数。【思路】一开始看到这道题......
  • 数据类型拓展与面试题解读
    整数拓展进制:在平时咱们生活中经常见到的例如通用于电脑识别的二进制、咱们生活中常用的十进制、工作中常见的八进制与十六进制。二进制:通常会以0b开头十进制:咱们生活中的数字八进制:通常以0开头十六进制:通常以0x开头​ 浮点数拓展(float、double)试题举例银行......
  • Codeforces Round 929 (Div. 3) 题解(D-G)
    比赛链接:https://codeforces.com/contest/1933官解暂未放出。质量不错的一场D3。CF1933D.TurtleTenacity:ContinualMods题意将数组\(a_{1..n}\ge1\)重排,问是否能使\(((a_1\mathbin{\rmmod}a_2)\mathbin{\rmmod}a_3)\cdots\mathbin{\rmmod}a_n\ne0\)......
  • 题解 P10196【[USACO24FEB] Lazy Cow P】
    总算铂金组场切一题。似乎做麻烦了,而且常数蛮大的,但是没啥思维难度,记录一下。对于每一个需求,我们将其放置在平面直角坐标系的\((m_i,b_i)\)位置。另外,自然有一个\((0,0)\)需求,也同样处理这个点。我们需要支持插入一个点的操作,并维护出答案。先考虑不需要动态插点,只在最后求......
  • 第十四届蓝桥杯个人题解
    a幸运的数主要是思路 遍历1-100000000每一层循环,首先将其每一位分到数组里,并记录位数,如果是偶数位再接着往下,比较前半和后半是否相等:通过加减最后结果是否为零来判断intmain(){  intnum=0;  for(inti=1;i<100000000;i++)  {    ints[9]={0};......
  • ABC338G evall 题解
    题意:给定一个由数字和加号和乘号组成的字符串,求出\(\sums(i,j)\)。其中\(s(i,j)\)表示\(i\)到\(j\)字符组成的表达式的值。考虑\(\text{dp}\)。设\(dp_{i}\)表示以\(i\)为起点的所有表达式的值之和。那么我们考虑以一些加号作为分界点来转移。假设\(i\)右边最......
  • CF1209G2 Into Blocks (hard version) 题解
    Description给你\(n\),\(q\),\(n\)表示序列长度,\(q\)表示操作次数。我们需要达成这么一个目标状态:如果存在\(x\)这个元素,那么必须满足所有\(x\)元素都必须在序列中连续。然后你可以进行这么一种操作,将所有的\(x\)元素的变为任意你指定的\(y\)元素,并且花费\(cnt[x......
  • 2024牛客寒假算法基础集训营6 题解 ( A,B,C,D,E,I)
    2024牛客寒假算法基础集训营6题解(A,B,C,D,E,I)A 宇宙的终结题意找到\([l,r]\)区间中有多少数恰好等于三个不同素数的乘积思路数据范围很小,可以考虑暴力,遍历\([l,r]\)区间内每个数,拿每个小于当前数的素数一直往下除,判断是否存在能被恰好3个素数整除的情况代码/********......
  • 题解 NKOJ2929 【[THUSC2014] 函数求解】
    代码:#include<iostream>#include<queue>#include<cstdio>#include<cmath>usingnamespacestd;typedefstruct{ intnxt; intend; intdis; doublecost;}Edge;constintN=2e3,M=400+7,K=80800+7;constdoubleep......
  • ABC294 EFG 题解
    E-2xNGrid题意给你一个\(2\timesL\)的网格,但是\(L\)很大,所以用以下形式压缩:将同一个颜色的连续段视为一个整体,那么每一行就可以用若干个二元组\((a_i,b_i)\)表示,其中\(a_i\)为颜色,\(b_i\)为连续段的长度。保证长度\(\le10^5\)。输入以上述形式压缩,现在让你求出......