Codeforces Round 887 (Div. 1) 题解

https://codeforces.com/contest/1852/problems

A. Ntarsis' Set

https://codeforces.com/contest/1852/problem/A

image

image

感觉不是很一眼。

nk 都是 2×105不能暴力,设当前集合为 1,2,,101000,那么被操作过一次的最小值就应该是 MEX(0,a1,a2,,an)

扩展一下,集合 S 被操作过一次的最小值就是 SMEX(0,a1,a2,,an)(其中 SkS 的第 k 小值)。

观察样例及其解释:


5 3
1 3 5 6 7
Day S Before S After
1 {1,2,3,4,5,6,7,8,9,10,} {2,4,8,9,10,}
2 {2,4,8,9,10,11,12,13,14,15,} {4,9,13,14,15,}
3 {4,9,13,14,15,16,17,18,19,20,} {9,14,18,19,20,}

设操作一次后的集合为 S,那么最小值就是 S1,能保留的最小的也就是第 S1 小的数,观察一下,下一个数就是 S 中第 S1 小的数,所以这样递归算就行了。

具体实现见代码。

/**
  * author : OMG_78
  * created: 2023-07-24-09.19.39
 **/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline bool ok (char c) {
  if (c < '0') return true;
  if (c > '9') return true;
  return false;
}
template < class Z >
inline void read (Z &tmp) {
  Z x = 0, f = 0;
  char c = getchar ();
  for ( ; ok (c) ; c = getchar ()) f = (c == '-') ? 1 : f;
  for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
  tmp = !f ? x : -x;
}
int n, k, cnt;
ll a[200005], b[210005][2], sm[210005];
inline ll qu (ll x) {
  int L = 1, R = cnt;
  while (R - L > 1) {
    int mid = L + R >> 1;
    if (x >= sm[mid - 1] + 1) L = mid;
    else R = mid;
  }
  if (x >= sm[R - 1] + 1) {
    x -= sm[R - 1], x --;
    return b[R][0] + x;
  }
  else {
    x -= sm[L - 1], x --;
    return b[L][0] + x;
  }
}
bool Memory_Ends;
signed main () {
  fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
  int _; read (_);
  while (_ --) {
    read (n), read (k);
    for (int i = 1;i <= n; ++ i) read (a[i]);
    if (a[1] != 1) {
      printf ("1\n");
      continue;
    }
    cnt = 0;
    for (int i = 1;i <= n; ++ i) {
      if (i != n) {
        if (a[i] + 1 <= a[i + 1] - 1) cnt ++, b[cnt][0] = a[i] + 1, b[cnt][1] = a[i + 1] - 1;
      }
      else {
        cnt ++;
        b[cnt][0] = a[n] + 1, b[cnt][1] = 9e18;
      }
    }
    for (int i = 1;i <= cnt; ++ i) sm[i] = sm[i - 1] + b[i][1] - b[i][0] + 1;
    ll u = b[1][0];
    -- k;
    while (k --) {
      u = qu (u);
    }
    printf ("%lld\n ", u);
  }
  fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
  return 0;
}

B. Imbalanced Arrays

https://codeforces.com/contest/1852/problem/B

image

image

考虑构造方案,显然 ai 大的最后的 bi 也会大,所以先以 ai 为关键字从大到小排序,考虑枚举一个 k(0kn),有 b1bk 是正的,bk+1bn 是负的,并且 b1b2bn;比 bi(1ik) 应该填 aii+1,不大于 i 绝对值的(相加必定大于 0,因为 ww 不同时出现)有 aii+1,大于 i 的绝对值的并且加和为正数,只有可能是正数,有 i1 个,所以 ai+aj>0j 的数量为 aii+1+i1ai 个。

bk+1bn 就可以倒着从大到小填。

最后考虑可能有解的 k 的个数,有 k 个正数,那么 a1,a2,,ak 一定至少为 k,因为有单调性,所以只需满足 akk;大的加小的为正数的方案数应该与小的加大的为正数的方案数相等,所以 i=1kaik2=i=k+1nai,可以证明(但是我不会 lol)满足条件的 k 最多只有 1 个。

最后检验一下就行了,如果实在满足不了就是无解。

/**
  * author : OMG_78
  * created: 2023-07-24-09.58.56
 **/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline bool ok (char c) {
  if (c < '0') return true;
  if (c > '9') return true;
  return false;
}
template < class Z >
inline void read (Z &tmp) {
  Z x = 0, f = 0;
  char c = getchar ();
  for ( ; ok (c) ; c = getchar ()) f = (c == '-') ? 1 : f;
  for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
  tmp = !f ? x : -x;
}
struct node {
  int id, w;
} qwq[100005];
ll sm[100005], qws[100005];
inline bool cmp (node p1, node p2) {
  return p1.w > p2.w;
}
int n, ans[100005];
inline bool solveq (int idx) {
  set < int > aq; aq.clear ();
  for (int i = 1;i <= n; ++ i) aq.insert (i);
  for (int i = 1;i <= idx; ++ i) {
    ans[i] = qwq[i].w - i + 1;
    if (ans[i] <= 0) {
      return false;
    }
    aq.erase (ans[i]);
  }
  for (int i = n;i > idx; -- i) {
    ans[i] = *aq.rbegin ();
    aq.erase (ans[i]);
    ans[i] = -ans[i];
  }
  for (int i = 1;i <= n; ++ i) {
    if (qwq[i].w && ans[qwq[i].w] + ans[i] <= 0) return false;
    if (qwq[i].w < n && ans[qwq[i].w + 1] + ans[i] >= 0) return false;
  }
  printf ("YES\n");
  for (int i = 1;i <= n; ++ i) qws[qwq[i].id] = ans[i];
  for (int i = 1;i <= n; ++ i) printf ("%d ", qws[i]);
  printf ("\n");
  return true;
}
inline void solve () {
  read (n);
  for (int i = 1;i <= n; ++ i) read (qwq[i].w), qwq[i].id = i;
  sort (qwq + 1, qwq + 1 + n, cmp);
  for (int i = 1;i <= n; ++ i) sm[i] = sm[i - 1] + 1ll * qwq[i].w;
  int idx = -1;
  for (int k = 0;k <= n; ++ k) {
    if (qwq[k].w >= k && sm[k] - (1ll * k) * (1ll * k) == sm[n] - sm[k]) {
      if (solveq (k)) return ;
    }
  }
  printf ("NO\n");
}
bool Memory_Ends;
signed main () {
  fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
  int _; read (_);
  while (_ --) solve ();
  fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
  return 0;
}

C. Ina of the Mountain

https://codeforces.com/contest/1852/problem/C

image

image

如果没有 modk 的限制,发现就是差分数组的正项求和,即 i=1nmax(0,aiai1)

可以将 modk 转化为将每个数事先加上若干个 k,然后就不用再考虑 modk,直接算即可。

考虑贪心地加 k

  • 首先 aiai1 加同样数量的 k

  • 如果 aiai1,贡献为 0,那最好,不要再动了。

  • 如果 ai>ai1,分两种情况:躺平,aiai1 的代价就可以了;给 [j,i)(1j<i) 的所有 ax 都加上一个 k,对差分数组的贡献就是 aj+kaj1。第二种情况考虑 反悔贪心

首先用一个堆存每一个点加上 k 对差分数组的贡献,aiai1 的贡献就是 ai+kai1,没啥好说的;ai>ai1 如果 aiai1 是最优的就直接加上,没啥好说的,否则就加上堆中最小的,就是反悔的过程,然后堆中加上 aiai1,方便以后反悔。

/**
  * author : OMG_78
  * created: 2023-07-25-09.39.18
 **/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
bool Memory_Begins;
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline bool ok (char c) {
  if (c < '0') return true;
  if (c > '9') return true;
  return false;
}
template < class Z >
inline void read (Z &tmp) {
  Z x = 0, f = 0;
  char c = getchar ();
  for ( ; ok (c) ; c = getchar ()) f = (c == '-') ? 1 : f;
  for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
  tmp = !f ? x : -x;
}
int n, k, a, prevq;
#define prev prevq
ll ans;
priority_queue < int, vector < int >, greater < int > > heap;
bool Memory_Ends;
signed main () {
  fprintf (stderr, "%.3lf MB\n", (&Memory_Begins - &Memory_Ends) / 1048576.0);
  int _; read (_);
  while (_ --) {
    read (n), read (k);
    prev = 0;
    while (!heap.empty ()) heap.pop ();
    ans = 0;
    for (int i = 1;i <= n; ++ i) {
      read (a);
      a %= k;
      if (prev > a) {
        heap.push (a + k - prev);
      }
      else {
        heap.push (a - prev);
        ans += 1ll * heap.top ();
        heap.pop ();
      }
      prev = a;
    }
    printf ("%lld\n", ans);
  }
  fprintf (stderr, "%.3lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
  return 0;
}
posted @   CountingGroup  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示