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

Codeforces Round 979 (Div. 2)

时间:2024-10-26 13:21:44浏览次数:9  
标签:std cnt cin int LL Codeforces 979 kN Div

目录

写在前面

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

赛时 E 看错题了变成神题了而且居然还口胡了一个自然根号的做法还写出来了然而样例没过最后才发现读错题了妈的。

掉分!

A 签到

\(b, c\) 即前缀最小值和最大值,显然最优的构造是把最大值和最小值放在前两个位置,答案即:

\[(n-1)\left(\max a_i - \min a_i\right) \]

//
/*
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;
    int mina = 1100, maxa = -1;
    for (int i = 1; i <= n; ++ i) {
      int a; std::cin >> a;
      mina = std::min(mina, a);
      maxa = std::max(maxa, a);
    }
    std::cout << (1ll * (n - 1) * (maxa - mina)) << "\n";
  }
  
  return 0;
}

B 构造

因为是 01 串且选的是子序列,所以并不需要关注选的位置,仅需关注选的字符种类即可。

设构造的串 \(t\) 里有 \(k\) 个 0,则 \(f(t) = 2^k - 1, g(t) = 2^n - 1 - f(t)\),则 \(|f(t) - g(t)| = |2^{k +1} - 2^n|\),

仅需取 \(k=n-1\) 即可令 \(|f(t)-g(t)| = 0\),于是随便构造一个有 \(n-1\) 个 0,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 T; std::cin >> T;
  while (T --) {
    int n; std::cin >> n;
    for (int i = 1; i <= n - 1; ++ i) std::cout << 0;
    std::cout << 1;
    std::cout << "\n";
  }
  return 0;
}

C 博弈

显然若第一个或最后一个字符为 1,则 Alice 必胜。

注意到题面中特别指出 and 运算优先级更高,则发现若有两个 1 相邻,则 Alice 一定可以在将两者之一的两侧均插入一个 or 从而必胜,否则若所有 1 均不相邻,则 Bob 可以通过优先级更高的 and 将所有 1 均变为 0;

于是仅需判断第一个字符、最后一个字符是否为 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 T; std::cin >> T;
  while (T --) {
    int n; std::cin >> n;
    std::string s; std::cin >> s;
    
    int flag = 0;
    for (int i = 0; i < n; ++ i) {
      if (i == 0 && s[i] == '1') flag = 1;
      if (i == n - 1 && s[i] == '1') flag = 1;
      if (0 < i && s[i] == '1' && s[i - 1] == '1') flag = 1;
    }
    std::cout << (flag ? "YES\n" : "NO\n");
  }
  return 0;
}

D 模拟

发现将操作分为 \(L, R\) 是无必要的,先把所有操作均转化为 \((i-1, i)\) 的形式。

发现如果在某个位置 \(i\) 前面有大于 \(i\) 的数,说明操作 \((i-1, i)\) 是必要的。因为每次询问排列均为初始状态,则于是必要操作的种类是不变的,仅需考虑维护当前已经有了多少必要操作即可。

可以通过桶简单实现。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, q, p[kN], premax[kN], sufmin[kN];
int need[kN], have[kN];
std::string s;
//=============================================================
//=============================================================
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 >> q;
    for (int i = 1; i <= n; ++ i) std::cin >> p[i], need[i] = have[i] = 0;
    std::cin >> s; s = "$" + s;

    for (int i = 1; i <= n; ++ i) premax[i] = std::max(premax[i - 1], p[i]);
    sufmin[n + 1] = n + 1;
    for (int i = n; i; -- i) sufmin[i] = std::min(sufmin[i + 1], p[i]);
    
    int cnt = 0, needcnt = 0;
    for (int i = 1; i <= n; ++ i) {
      if (s[i] == 'L') ++ have[i - 1];
      if (s[i] == 'R') ++ have[i];
    }
    for (int i = 1; i < n; ++ i) {
      if (premax[i] > i || sufmin[i + 1] <= i) need[i] = 1;
      needcnt += need[i];
      cnt += (need[i] && have[i]);
    }

    while (q --) {
      int x; std::cin >> x;
      cnt -= (need[x - 1] && have[x - 1]);
      cnt -=  (need[x] && have[x]);

      if (s[x] == 'L') -- have[x - 1], ++ have[x], s[x] = 'R';
      else -- have[x], ++ have[x - 1], s[x] = 'L';

      cnt += (need[x - 1] && have[x - 1]);
      cnt += (need[x] && have[x]);

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

E 组合数学

结论缝合题。首先要推出来两个结论:

给定 \(n\) 个整数,记其中权值 \(i\) 的数量为 \(\operatorname{cnt}_i\),则 \(\operatorname{mex}\le i\) 的子集数量为:\(s_i = 2^{n} - 2^{\operatorname{cnt}_i}\),简单容斥可知 \(\operatorname{mex}= i\) 的子集数量为 \(s_i - s_{i - 1}\)。

给定 \(n\) 个整数,记其中权值 \(i\) 的数量为 \(\operatorname{cnt}_i\),将它们分为若干个集合 \(S_1\sim S_k\),最大化 \(\sum_j \operatorname{mex}(S_j)\),显然贪心地分配,每次将当前所有权值都拿出一个来创建一个新集合即可,最大价值为:\(\operatorname{cnt}_0 + \min(\operatorname{cnt}_0, \operatorname{cnt}_1) + \min(\operatorname{cnt}_0, \operatorname{cnt}_1, \operatorname{cnt}_2) + \cdots\)。

因为是选子序列,于是仅需考虑选择的各种权值的数量即可。根据上述结论,考虑升序枚举所有权值 \(i\),考虑该种权值产生了 \(j\) 的贡献(即分出来的子集中恰有 \(j\) 个 \(\operatorname{mex}> i\))的子序列数量有多少。考虑套用结论 1,先求 \(s_j\) 表示该种权值产生了 \(\ge j\) 的贡献的方案数 \(s_j\),则对于权值 \(0\sim i\),都需要选至少 \(j\) 个,对于其他权值任选,可以简单通过组合意义+前缀和得到,则总贡献即为:

\[\sum_{j=1}^{\min(\operatorname{cnt}_0, \cdots, \operatorname{cnt}_i)} j\times (s_{j + 1} - s_{j}) \]

实现详见代码,总时间复杂度 \(O(n)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const LL p = 998244353;
//=============================================================
int n, a[kN];
LL pw2[kN], fac[kN], invfac[kN], cnt[kN], sum[kN], pre[kN];
//=============================================================
LL C(LL x_, LL y_) {
  if (y_ == 0) return 1;
  if (y_ > x_) return 0;
  return fac[x_] * invfac[y_] % p * invfac[x_ - y_] % p;
}
LL qpow(LL x_, LL y_) {
  LL ret = 1;
  while (y_) {
    if (y_ & 1) ret = ret * x_ % p;
    x_ = x_ * x_ % p, y_ >>= 1ll;
  }
  return ret;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  pw2[0] = fac[0] = invfac[0] = 1;
  for (int i = 1; i < kN; ++ i) {
    pw2[i] = 2ll * pw2[i - 1] % p;
    fac[i] = fac[i - 1] * i % p;
  }
  invfac[kN - 1] = qpow(fac[kN - 1], p - 2);
  for (int i = kN - 2; i; -- i) invfac[i] = invfac[i + 1] * (i + 1) % p;

  int T; std::cin >> T;
  while (T --) {
    std::cin >> n;
    for (int i = 0; i <= n; ++ i) cnt[i] = 0;
    for (int i = 1; i <= n; ++ i) std::cin >> a[i], ++ cnt[a[i]];

    LL ans = 0, mincnt = kN, sumcnt = 0;
    for (int i = 1; i <= n; ++ i) pre[i] = 1;

    for (int i = 0; i < n; ++ i) {
      if (cnt[i] == 0) break;
      for (int j = 0; j <= cnt[i] + 1; ++ j) sum[j] = 0;
      
      LL sumc = 0;
      mincnt = std::min(mincnt, cnt[i]), sumcnt += cnt[i];
      for (int j = cnt[i]; j; -- j) {
        sumc = (sumc + C(cnt[i], j)) % p;
        pre[j] = pre[j] * sumc % p;
      }
      for (int j = 1; j <= mincnt; ++ j) {
        sum[j] = 1ll * pre[j] * pw2[n - sumcnt] % p;
      }
      for (int j = 1; j <= mincnt; ++ j) {
        ans += 1ll * j * (sum[j] - sum[j + 1] + p) % p;
        ans %= p;
      }
    }
    std::cout << ans << "\n";
  }
  return 0;
}

写在最后

学到了什么:

  • E:考虑单个元素对集合的贡献之和。

标签:std,cnt,cin,int,LL,Codeforces,979,kN,Div
From: https://www.cnblogs.com/luckyblock/p/18503964

相关文章

  • Codeforces Round 981 (Div. 3)A-D题解
    CodeforcesRound981(Div.3)A.SakurakoandKosukeSakurakoandKosukedecidedtoplaysomegameswithadotonacoordinateline.Thedotiscurrentlylocatedinposition\(x=0\).Theywillbetakingturns,andSakurakowillbetheonetostart.Ont......
  • Codeforces Round 981 (Div. 3) G
    G.SakurakoandChefir因为没有找到类似的题解,顺便记录下来题目给定一棵树,树上有\(n\)个顶点,以顶点\(1\)为根。樱子带着她的猫Chefir穿过这棵树,樱子走神了,Chefir跑开了。为了帮助樱子,浩介记录了他的\(q\)次猜测。在\(i\)次猜测中,他假设Chefir在顶点\(v_i\)迷路,......
  • 倒计时功能实现:认识了css选择器 div[id^=“countdown-“]
    html倒计时<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>倒计时功能实现</ti......
  • 【CodeForces训练记录VP】Codeforces Round 933 (Div. 3)
    https://codeforces.com/contest/1941训练情况50min后罚坐反思C题刚开始思路错了,以为是删字符串最后面,然后漏考虑掉两字符串部分拼接的情况A题直接模拟,求\(a_i+b_j\lek\)的对数。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;voidsolve......
  • Codeforces Round 972 (Div. 2)
    CodeforcesRound972(Div.2)总结A#include<bits/stdc++.h>usingnamespacestd;intn;chara[]={'a','e','i','o','u'};voidsolve(){cin>>n;intx=n/5,y=n%5;for(inti=0;i<5;......
  • CodeForces - 788C - 完全背包
    题目表示(x1*a[1]+x2*a[2]+...+xk*a[k])/((x1+x2+...+xk)*1000)=n/1000,可以推出(x1*a[1]+x2*a[2]+...+xk*a[k])=n*(x1+x2+...+xk),进而得出(x1*(a[1]-n)+x2*(a[2]-n)+...+xk*(a[k]-n))=0,这样处理之后就和我之前......
  • Codeforces Round 980 (Div. 2)
    CodeforcesRound980(Div.2)总结A简单小学算数题。如果\(b\lea\),直接输出\(a\)。否则,列方程\(a-x=b-2x\),\(x=b-a\),输出\(a-x\),即\(2a-b\)。#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<c......
  • [算法题解] Codeforces round 979 --D. QED's Favorite Permutation
    题目链接:https://codeforces.com/contest/2030/problem/D题目:题解:FavotitePermutation即每个数满足i=p[i];此题中,p数组每次询问后保持不变,s根据询问而改变。因此每次需要进行交换的数的位置是相同的,只需要检验s变更后,操作能否满足交换需求与否。故创建需数组need,预处理nee......
  • Codeforces Round 966 (Div. 3) A - G
    linkvp赛时过了ABD,CE没做出来,唐完了eee感觉自己真的可以退役了A-PrimaryTaskB-SeatinginaBusC-NumericStringTemplate这题很简单,开两个map扫一遍就可以了,但是赛时我只开了一个,然后居然没调出来qwq,降智D-RightLeftWrong很显然的贪心,最左边配对......
  • HTML布局常用标签——div和span
    HTML布局常用标签——div和span在HTML的世界里,div和span是两位不可或缺的老朋友,它们虽然看似简单,却在网页布局和样式设计中发挥着举足轻重的作用。今天,我们就来聊聊这两位“无意义”却极其实用的标签——div和span。一、div:块级元素的大块头1.定义与特点div,全称“division”,......