Codeforces Global Round 27

写在前面

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

前期犯唐 C 不会呃呃,后面 E 会了然而跑去写什么狗屁三分似掉了也没救回来。

本来想着一场上橙的,这下又掉分了哈哈。

厌学中。

A 签到

发现受到影响的位置仅有三种:

  • 在第 \(r\) 行,\(c+1\sim m\) 列的,左移一位;
  • 在第 \(r+1\sim n\) 行,第 1 列的,移动到上一行最后;
  • 在第 \(r+1\sim n\) 行,第 \(2\sim m\) 列的,左移一位。

三种位置的贡献求和即可。

//
/*
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, m, r, c; std::cin >> n >> m >> r >> c;
    LL ans = 0;
    ans += 1ll * (m - c);
    ans += 1ll * (n - r) * (m - 1 + 1);
    ans += 1ll * (n - r) * 1 * (m - 1);
    std::cout << ans << "\n";
  }
  return 0;
}

B 结论

显然仅需考虑模 66 为 0。

一个显然的想法是先构造为全 3 的数,然后把某些位改成 6。

打了个表发现对于全 3 的数,模 66 的余数只有 3 和 33 两种情况,于是根据样例:

  • 若余数为 33,考虑再加 33,即将后两位改成 6 即可;
  • 若余数为 3,考虑再加 3033 即可。

若无法加则无解。

//
/*
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 ans;
    LL sum = 0;
    for (int i = 1; i <= n; ++ i) ans.push_back('3'), sum = (10 * sum + 3) % 66;

    if (sum == 33) {
      ans[n - 1] = '6', ans[n - 2] = '6';
    } else {
      if (n == 1 || n == 3) ans = "-1";
      else ans[n - 1] = '6', ans[n - 2] = '6', ans[n - 4] = '6';
    }
    std::cout << ans << "\n";
  }
  return 0;
}

C 构造

妈的不会构造被鲨了。

首先通过样例猜测,当 \(n\) 为奇数时 \(k=n\)\(n\) 为偶数时 \(k = 2^{\left\lfloor\log_2 n\right\rfloor + 1} - 1\),即两种情况都能取到上界。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, ans[kN];
LL k;
//=============================================================
void check() {
  int temp = 0;
  for (int i = 1; i <= n; ++ i) {
    if (i % 2 == 0) temp |= ans[i];
    else temp &= ans[i];
  }
  std::cout << "---" << temp << "\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 --) {
    std::cin >> n;
    
    if (n & 1) {
      k = n;
      ans[n] = n;
      ans[n - 1] = n - 1;
      ans[n - 2] = 1;
      for (int i = 1; i <= n - 3; ++ i) ans[i] = i + 1;
    } else {
      k = (1ll << (((LL) log2(n)) + 1)) - 1l;
      std::map<int, bool> vis;
      std::vector<int> b[2];
      int len = n;

      ans[n] = n;
      ans[n - 1] = k ^ n;
      if ((k ^ n) == 1) {
        len = 2;
      } else {
        len = 4;
        ans[n - 2] = ans[n - 1] - 1;
        ans[n - 3] = 1;
      }
      for (int i = n - len + 1; i <= n; ++ i) vis[ans[i]] = 1;
      for (int i = 1; i <= n; ++ i) if (!vis[i]) b[i % 2].push_back(i);
      for (int i = 1, j = 0; i <= n - len; ++ i, j ^= 1) ans[i] = b[j].back(), b[j].pop_back();
    }
    // check();
    std::cout << k << "\n";
    for (int i = 1; i <= n; ++ i) std::cout << ans[i] << " ";
    std::cout << "\n";
  }
  return 0;
}

D 贪心,单调栈

先把每个数 2 的因子的次数 \(\operatorname{cnt}_i\) 求出来,记 \(a_i\) 除掉所有 2 的因子后剩下的部分为 \(b_i\)

发现前缀 \(1\sim i\) 的最优操作方案,一定是将前缀 \(1\sim i - 1\) 的操作方案中,某些位置的 2 的因子全部贡献给 \(a_i\) 得到的。显然只要 \(b_j\le a_i = 2^{\operatorname{cnt}_i}\times b_i\) 就应当产生贡献,又发现一个位置只能向其他位置贡献一次,于是考虑单调栈维护当前有哪些位置能向之后产生贡献,每次加入一个数 \(a_i\) 时不断弹栈将贡献给到 \(a_i\) 即可。

注意上述判断条件 \(b_j\le 2^{\operatorname{cnt}_i}\times b_i\) 中,当 \(a_i\) 获得了若干 2 的幂后会变得很大,因此需要单独写个比较函数,特判 \(\operatorname{cnt}_i\) 较大时直接返回结果即可。

还需要写个快速幂,总时间复杂度 \(O(n\log v)\) 级别。

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const LL p = 1e9 + 7;
//=============================================================
int n;
LL cnt2[kN], a[kN], b[kN], pw2[kN];
int top, st[kN];
//=============================================================
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;
}
bool cmp(int p1_, int p2_) {
  if (pw2[p2_] > 30) return 1;
  return (1ll << pw2[p2_]) * b[p2_] >= b[p1_];
}
//=============================================================
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;
    for (int i = 1; i <= n; ++ i) cnt2[i] = 0;
    for (int i = 1; i <= n; ++ i) std::cin >> a[i], b[i] = a[i];
    for (int i = 1; i <= n; ++ i) {
      while (b[i] % 2 == 0) ++ cnt2[i], b[i] /= 2;
    }
    
    top = 0;
    LL ans = 0;
    for (int i = 1; i <= n; ++ i) {
      ans += b[i];

      pw2[i] = cnt2[i];
      while (top && cmp(st[top], i)) {
        pw2[i] += pw2[st[top]];
        ans -= b[st[top]] * (qpow(2, pw2[st[top]]) - 1 + p) % p;
        ans = (ans + p) % p;

        pw2[st[top]] = 0;
        -- top;
      }
      st[++ top] = i;
      ans += b[i] * (qpow(2, pw2[i]) - 1 + p) % p;
      ans %= p;

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

E 结论,数论分块

//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const LL kInf = 1e18 + 2077;
//=============================================================
LL x, y, z, k, ans;
//=============================================================
void check(LL r_, LL c1_, LL d1_) {
  LL c2 = kInf;

  for (LL r = r_ * k + k, l; r > r_ * k; r = l - 1) {
    l = std::max(r_ * k + 1, (LL) ceil(1.0 * (z - d1_) / ceil(1.0 * (z - d1_) / r)));
    c2 = std::min(c2, x * (l - r_ * k) + y * ((LL) ceil(1.0 * (z - d1_) / l)));
  }

  ans = std::min(ans, c1_ + c2);
}
//=============================================================
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 >> x >> y >> z >> k;
    
    ans = kInf;
    for (LL round = 0; ; ++ round) {
      LL c1 = round * (k * x + y);
      LL d1 = round * (round + 1ll) / 2ll * k;
      if (d1 >= z) {
        ans = std::min(ans, c1);
        break;
      }
      check(round, c1, d1);
    }
    std::cout << ans << "\n";
  }
  return 0;
}

写在最后

怎么一堆思维结论题+打表,把我这种没脑子的呆瓜鲨了。

好想死掉。

posted @ 2024-10-28 04:06  Luckyblock  阅读(148)  评论(0编辑  收藏  举报