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

Codeforces Round 924 (Div. 2)

时间:2024-02-19 23:56:34浏览次数:28  
标签:std le frac int LL Codeforces times Div 924

目录

写在前面

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

终于把欠下的一堆题补上了呃呃

天使骚骚共通线什么构式呃呃,一周目就想走老师线直通单身笑死我了。

A

签到。

发现等分后重新拼接可以得到 \(\frac{x}{2}\times 2y\) 与 \(\frac{y}{2}\times 2x\) 的两个矩形,检查它们是否与 \(x\times y\) 或 \(y\times x\) 相同即可。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define mp std::make_pair
#define pii std::pair<int,int>
#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 x, y; std::cin >> x >> y;
    std::map <pii, int> m;
    m[mp(x, y)] = 1, m[mp(y, x)] = 1;

    int flag = 0;
    if (x % 2 == 0) {
      if (m[mp(x / 2, 2 * y)] == 0) flag = 1; 
    } 
    if (y % 2 == 0) {
      if (m[mp(2 * x, y / 2)] == 0) flag = 1; 
    }
    if (flag) std::cout << "YES\n";
    else std::cout << "NO\n";
    /*
    x, y
    y, x
    
    x/2, 2y

    y/2, 2x
    */
  }
  return 0;
}

B

知识点:双指针。

显然重复元素只会贡献一次,于是先去重。

然后考虑对于元素 \(b_1<b_2<\cdots<b_k\),若它们加排列中元素后能够相等,则一定有 \(b_1 + n\ge b_k + 1\),即 \(b_k - b_1\le n - 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::map <int, int> m;
    std::vector <int> v;
    for (int i = 1; i <= n; ++ i) {
      int x; std::cin >> x;
      if (m.count(x)) continue;
      m[x] = 1;
      v.push_back(x);
    }
    std::sort(v.begin(), v.end());
    int l = 0, r = 0;
    while (r < v.size() && v[r] + 1 <= v[l] + n) ++ r;
    -- r;
    
    int ans = r - l + 1;
    while (l < v.size()) {
      ++ l;
      while (r < v.size() && v[r] + 1 <= v[l] + n) ++ r;
      -- r;
      ans = std::max(ans, r - l + 1);
    }

    std::cout << ans << "\n";
  }
  return 0;
}

C

知识点:数学

纯粹的数学题。

首先当 \(k< x\) 或 \(k\ge n\) 时显然不满足题意。

对于一满足题意的 \(k(k\ge x)\),数列中 1 的位置可表示为 \(1 + y\times (2k-2) (y\ge 0)\),则 \(x\) 的位置可表示为 \(1 + (y - 1)\times (2k-2) + (x - 1) (y\ge 1)\) 与 \(1 + y\times (2k-2) - (x - 1) (y\ge 1)\),讨论一下:

  • 若 \(n = 1 + (y - 1)\times (2k-2) + (x - 1) (y\ge 1)\),则有:

    \[2(k - 1)(y-1) = n - x \]

    于是考虑枚举 \(n-x\) 的所有因数 \(d=2\times (k-1)\) 解得 \(k=\frac{d}{2} + 1\),若满足 \(x\le \frac{d}{2} + 1<n\) 且为整数则找到了一个解。

  • 若 \(n = 1 + y\times (2k-2) - (x - 1) (y\ge 1)\),则有:

    \[2(k-1)y = n + x - 2 \]

    同理枚举 \(n+x-2\) 的所有因数求 \(k\) 的解即可。

总时间复杂度 \(O\left(t\sqrt{n+x}\right)\) 级别。

//知识点:数学
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
void Solve() {
  LL x, n; std::cin >> n >> x;

  LL d1 = n - x, d2 = n + x - 2;
  LL ans = 0;
  std::map <LL, bool> m;

  if (d1 > 0) {
    for (LL i = 1; i * i <= d1; ++ i) {
      if (d1 % i != 0) continue;
      if (!m.count(i) && (i % 2 == 0) && (i / 2 + 1 < n) && (i / 2 + 1 >= x)) {
        ans ++, m[i] = 1;
      }
      if (!m.count(d1 / i) && ((d1 / i) % 2 == 0)  && ((d1 / i) / 2 + 1 < n) && ((d1 / i) / 2 + 1 >= x)) {
        ans ++, m[d1 / i] = 1;
      }
    }
  }
  if (d2 > 0) {
    for (LL i = 1; i * i <= d2; ++ i) {
      if (d2 % i != 0) continue;
      if (!m.count(i) && i % 2 == 0 && (i / 2 + 1 < n) && (i / 2 + 1 >= x)) {
        ans ++, m[i] = 1;
      }
      if (!m.count(d2 / i) && ((d2 / i) % 2 == 0) && ((d2 / i) / 2 + 1 < n) && ((d2 / i) / 2 + 1 >= x)) {
        ans ++, m[d2 / i] = 1;
      }
    }
  }
  std::cout << ans << "\n";
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    Solve();
  }
  return 0;
}
/*
1
10 1

5
10 1
10 2
10 3
10 4
10 5

1 2 1 2 1 2 1 2 1 2
1 2 3 2 1 2 3 2 1 2
1 2 3 4 3 2 1 2 3 4
1 2 3 4 5 4 3 2 1 2
1 2 3 4 5 6 5 4 3 2
1 2 3 4 5 6 7 6 5 4
1 2 3 4 5 6 7 8 7 6
1 2 3 4 5 6 7 8 9 8
*/

D

知识点:三分

位于不同小组的同一种族的两个体才会产生贡献,则当小组数 \(k\) 确定时,对于每个种族最优的分配方案是将所有个体均分到 \(k\) 个小组中。则此时若某种族有 \(c\) 个个体,则有 \(r = c\bmod k\) 个小组有 \(\left\lfloor\frac{c}{k}\right\rfloor + 1\) 个个体,其他 \(k-r\) 个小组有 \(\left\lfloor\frac{c}{k}\right\rfloor\) 个个体,贡献即为:

\[f= r \left(\left\lfloor\frac{c}{k}\right\rfloor + 1\right) \left(c - \left\lfloor\frac{c}{k}\right\rfloor - 1\right) \times b + (k - r) \left\lfloor\frac{c}{k}\right\rfloor \left(c - \left\lfloor\frac{c}{k}\right\rfloor\right)\times b \]

则最终的总贡献值为:

\[g = \sum_{i=1}^{n} f_i - (k-1)\times x \]

观察多项式 \(g\) 的形式显然总贡献 \(g\) 是关于小组数量 \(k\) 的单峰函数,三分求函数极值点即可。

总时间复杂度 \(O(n\log_{3}\max\{c_i\})\) 级别。

//知识点:三分
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const int kInf = 1e9 + 2077;
//=============================================================
int n, b, x, c[kN];
//=============================================================
LL Check(LL mid_) {
  LL ret = -1ll * (mid_ - 1) * x, d = 0;
  for (int i = 1; i <= n; ++ i) {
    LL k = c[i] / mid_, r = c[i] % mid_;
    d += 1ll * (mid_ - r) * k * (c[i] - k) * b;
    d += 1ll * r * (k + 1) * (c[i] - k - 1) * b;
  }
  return ret + d / 2ll;
}
void Solve() {
  std::cin >> n >> b >> x;
  for (int i = 1; i <= n; ++ i) std::cin >> c[i];
  std::sort(c + 1, c + n + 1);
  
  LL ans = 0;
  int l = 1, r = 2 * c[n];
  for (; l < r; ) {
    int mid1 = l + (r - l) / 3, mid2 = r - (r - l) / 3;;
    LL ret1 = Check(mid1), ret2 = Check(mid2);
    ans = std::max(ans, std::max(ret1, ret2));
    if (ret1 < ret2) {
      l = mid1 + 1;
    } else {
      r = mid2 - 1;
    }
  }
  ans = std::max(ans, std::max(Check(l), Check(r)));
  std::cout << ans << "\n";
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  while (T --) {
    Solve();
  }
  return 0;
}

E

知识点:DP,构造

赛时没想到能 DP 预处理,恼弹一个。

首先所有位置均有 \(x\bmod y\) 的贡献,先令 \(s\) 与所有位置减去 \(n\times (x\bmod y)\)。此时所有位置均为 \(y\) 的倍数,若有解则 \(s\) 一定也为 \(y\) 的倍数,于是再令 \(s\) 与所有位置除以 \(y\),则此时要构造的数列形态为:

\[\frac{x - x\bmod y}{y}, \frac{x - x\bmod y}{y} + 1, \cdots, 0, 1, 2, \cdots, 0, 1, 2, \cdots \]

数列合法当且仅当数列之和为 \(s\)。

考虑枚举第一段 \(\frac{x - x\bmod y}{y}, \frac{x - x\bmod y}{y} + 1, \cdots\) 的长度 \(i\) 并检查使用剩下的位置 \(i+1\sim n\) 构造若干 \(0, 1, \cdots\) 能否凑出 \(s - \sum_{1\le j\le i} a_j\)。

上述检查对象可以 DP 预处理。具体地,记 \(f_{i}\) 表示凑出 \(i\) 最少需要多少个位置,初始化 \(f_{0}=0, \forall 1\le i\le s,\ f_i = \infin\)。转移时对于每个 \(i\) 枚举向后添加一段和为 \(j\) 长度为 \(k\) 的 \(0, 1, \cdots\),则有:

\[f_{i} + k\rightarrow f_{i+j} (i+j\le s) \]

注意为了输出方案还需要记录转移前驱。

转移过程中限制了 \(i+j\le s\),而 \(j\) 的值是关于 \(k\) 的二次函数,则有 \(1\le j\le \sqrt{s}\) 成立,则上述 DP 时间复杂度为 \(O\left(s\sqrt{s}\right)\) 级别。

预处理后按照上述思路枚举第一段 \(\frac{x - x\bmod y}{y}, \frac{x - x\bmod y}{y} + 1, \cdots\) 的长度 \(i\),再检查 \(f_{s - \sum_{1\le j\le i} a_j} \le n - i\) 是否成立即可。若成立则找到一组合法构造,令前 \(i\) 个位置为枚举的第一段,\([i + 1, i + f_{s - \sum_{1\le j\le i} a_j}]\) 为预处理的答案,剩余位置补 0,然后乘 \(y\) 加 \(x\bmod y\) 还原即可。

枚举的第一段长度最大为 \(O\left(\sqrt{s}\right)\) 级别,则总时间复杂度 \(O\left(s\sqrt{s} + n\right)\) 级别。

注意 \(f\) 不需要每组数据都进行预处理。

没开 LL WA 了发,警醒!

//知识点:DP,构造
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const int kInf = 1e9 + 2077;
//=============================================================
int n, x, y;
LL s;
int f[kN], from[kN], g[kN];
std::vector <int> ans;
//=============================================================
void DP(int lim_) {
  f[0] = 0;
  for (int i = 1; i <= lim_; ++ i) f[i] = kInf;

  for (int i = 0; i <= lim_; ++ i) {
    for (int j = 1, k = 1; i + j <= lim_; ++ k, j += k) {
      if (f[i] + k + 1 < f[i + j]) {
        f[i + j] = f[i] + k + 1;
        g[i + j] = k + 1;
        from[i + j] = i;
      }
    }
  }
}
void Solve() {
  std::cin >> n >> x >> y >> s;
  s -= 1ll * n * (x % y);
  if (s < 0 || s % y != 0) {
    std::cout << "NO\n";
    return ;
  }
  int r = x % y;
  x = (x - r) / y, s /= y;

  ans.clear();
  ans.push_back(x);
  LL s1 = x;
  for (int i = 1; i <= n; ++ i) {
    if (s1 > s) break;
    if (f[s - s1] <= n - i) {
      std::cout << "YES\n";
      for (int j = s - s1; j; j = from[j]) {
        for (int k = 1; k <= g[j]; ++ k) {
          ans.push_back(k - 1);
        }
      } 
      while ((int) ans.size() < n) ans.push_back(0);
      for (auto j: ans) std::cout << r + j * y << " ";
      std::cout << "\n";
      return;
    }
    ans.push_back(x + i);
    s1 += x + i;
  }
  std::cout << "NO\n";
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int T; std::cin >> T;
  DP(kN - 10);
  while (T --) Solve();
  return 0;
}
/*
1
1 1 2 1
*/

F

gugugu~

写在最后

学到了什么:

  • D:若可将贡献写成多项式形式,观察性质。
  • E:DP 预处理构造方案,开 LL

标签:std,le,frac,int,LL,Codeforces,times,Div,924
From: https://www.cnblogs.com/luckyblock/p/18022199

相关文章

  • Codeforces Round 927 (Div. 3)(A~F)
    目录ABCDEFA第一个遇到连续两个荆棘的地方就不能再赢金币了。所以统计连续两个荆棘之前的所有金币#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=(a);i<=(b);++i)#definefep(i,a,b)for(inti=(a);i>=(b);--i)#definepiipai......
  • Codeforces Round 927 (Div. 3)
    CodeforcesRound927(Div.3)A-ThornsandCoins解题思路:出现连续两个障碍之前,所有金币都能拿到。代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;usingpii=pair<ll,ll>;#definefifirst#definesesecondusingi128=__int128_t;......
  • D. Divisible Pairs
    原题链接题解如果\((a_i+a_j)\mod\x==0\)那么\((a_i\mod\x+a_j\mod\x)\mod\x==0\)如果\((a_i-a_j)\mod\y==0\)那么\(a_i\mod\y==a_j\mod\y\)所以我们可以把每个\(a\)的求模情况存下来,\(a[i]\)的贡献为其前面的\(a\)出现的对应求模情况数量\(co......
  • Codeforces Round 927 (Div. 3)
    CodeforcesRound927(Div.3)C.LR-remaindersDescription给定一个长度为\(n\)的数组\(a\)和\(n\)个指令,每条指令为\(\texttt{L,R}\)中的一种。依次处理每个指令:首先,输出\(a\)中所有元素的乘积除以\(m\)的余数。然后,如果当前指令为\(\textttL\),则移除数组......
  • Codeforces Round 927 (Div. 3)
    A传送门  根据题意每一步只能走一步或者两步,很显然如果有连续的两个荆棘就不能走了,在不能走之前是一定可以把路上的金币全捡起来所以只需要边捡金币边判断是否能继续走下即可。#include<bits/stdc++.h>usingll=longlong;typedefstd::pair<int,int>PII;typedef......
  • Codeforces Round 923 (Div. 3)
    A.MakeitWhite#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;usingi64=longlong;usingi128=__int128;usingldb=longdouble;#defineinti64usingvi=vector<int>;usingpii=pair<int,int>;usingvii......
  • Codeforces 1661F Teleporters
    先考虑贪心,令\(f(x,k)\)为满足\(\sum\limits_{i=1}^ks_i=x,s_i\in\mathbb{N}_+\)的\(s\)的\(\sum\limits_{i=1}^ks_i^2\)的最小值。也就是题目中在两个固定的点中放\(k-1\)个点这两个点中的最小贡献。平均分肯定是最优的,可以通过\(x\bmodk\)的值\(O(......
  • CF926 Div.2
    C.SashaandtheCasino赌场规则:如果下注\(y(y>0)\)元,如果赢了则除了\(y\)元外,额外获得\(y\times(k-1)\)元,否则则输掉\(y\)元;并且你不能连续输超过\(x\)次最初,你有\(a\)枚硬币,询问是否能够赢取任意数量的硬币题解:思维考虑这样一种策略:假设前面一直输,保......
  • SMU Winter 2024 div2 ptlks的周报Week 3(2.12-2.18)
    这周主要加强了对知识点的掌握。P10161[DTCPC2024]小方的疑惑10从题目可以得知a个连续括号贡献为a(a+1)/2,代价为2a。要求总贡献恰为k,且代价不高于n。一开始我想到了模拟,先取一个贡献低于k最大的a,剩下的再直接在外面套括号,结果wa。又想到可以分出多个a来组成k,就用递归,每次......
  • Codeforces Round 903 (Div. 3)
    题目链接A.按题意模拟字符串find函数if(x.find(s)==string::npos)//没找到#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;#defineinf0x3f3f3f3fvoidsolve(){intn,m;cin>>n>>m;stringx,s;cin>>x&g......