Codeforces Round #687


Prison Break

题意是,给你一个 \(n \times m\) 的矩阵,然后让你求这个矩阵中到 \((r, w)\) 的最远距离是多大。

模拟即可。

#include <cstdio>
using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

int main() {
  int T;
  scanf("%d", &T); 
  while (T--) {
    scanf("%d%d%d%d", &a, &b, &c, &d);
    int ans1 = c - 1 + abs(b - d);
    int ans2 = c - 1 + d - 1;
    int ans3 = abs(a - c) + d - 1;
    int ans4 = abs(a - c) + abs(b - d);
    cout << max(ans1, max(ans2, max(ans3, ans4))) << "\n";
  } 
} 

Repainting Street

一共有 n 个颜色,每次可以将最多 k 个方块粉刷成多种颜色,然后问你最少刷多少次之后颜色都相同。

可以发现颜色数很少,可以枚举每个的颜色数,暴力算将所有方块都染成这种颜色需要的方案书就行了,对答案取最小值。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
#define M 1010

using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int T;
int n, m, a[N];

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int main() {
  T = read();
  while (T--) {
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    int minn = inf;
    for (int i = 1; i <= 300; i++) {
      int sum = 0;
      for (int j = 1; j <= n; j++)
        if (a[j] != i) {
          sum++;
          j = j + m - 1;
        }
      minn = min(minn, sum);
    }
    cout << minn << "\n";
  }
}

Bouncing Ball

猜俩结论,显然操作 \(1\) 仅会修改对答案有贡献的位置。且操作的顺序一定是若干次操作 \(2\) 加上若干次操作 \(1\)
第二个结论正确性显然,若先进行一次操作 \(1\) 再进行操作 \(2\),之前修改的 \(1\) 可能会移动到对答案没有贡献的位置上。不如先进行操作 \(2\),再修改对答案有贡献的位置。

数据范围不大,考虑枚举操作 \(2\) 进行的次数 \(i\),新的对答案有贡献的位置为初始序列的 \((p+i)+q \times k\)
发现步长没有改变,考虑预处理 \(f_j\) 表示 \((p+i)=j\) 时,有贡献位置上 \(0\) 的个数,显然有:

\[f_i = \begin{cases} [a_j = 0] & (j + k > n)\\ f_{j + k} + [a_j = 0] & (j + k \le n) \end{cases} \]

则操作 \(2\) 进行 \(i\) 次的最小代价为 \(f_{p+i} \times x+i\times y\),取最小值即为答案。
总时间复杂度 \(\operatorname{O}{n}\)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
#define N 100010
#define M 1010

using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f3f3f3f3f;
int T, n, p, k;
int a[N], num[N], x, y;
int sum[N];

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

signed main() {
  T = read();
  while (T--) {
    memset(a, 0, sizeof a);
    memset(sum, 0, sizeof sum);
    memset(num, 0, sizeof num);
    n = read(), p = read(), k = read();
    for (int i = 1; i <= n; i++) {
      char sy;
      cin >> sy;
      a[i] = sy - '0';
    }
    x = read(), y = read();
    int ans = inf;
    for (int i = n; i >= 1; i--)
      if (a[i] == 0) sum[i] = sum[i + k] + 1;
      else sum[i] = sum[i + k];
    for (int i = 0; i <= n - p; i++)
      ans = min(ans, sum[i + p] * x + i * y);
    cout << ans << "\n";
  }
}

XOR-gun

结论,暴力。

有一些显然的性质。

  • 使得该数列 不单调不降,即存在合并后的两个位置,使得前一个 大于 后一个,以下称它为断点。

  • 被操作的位置一定是包含上述断点的一段区间,该断点前的部分构成较大的数,该断点后的部分构成较小的数。正确性显然。为了保证代价最小,断点不可能存在两个。为了使断点位置满足条件,需要对它前后分别操作。

于是可以考虑暴力枚举断点以及左右的区间,求得最小代价,复杂度 \(\operatorname{O}(n^3)\)

观察题目的特殊性质,从位运算的角度考虑,可以发现:
如果有三个连续的数的最高位相同,则可将后面两个异或起来消去最高位,使得第一个数大于后面的数。仅需操作 \(1\) 次即可。
又数列单调不降,则最长的使得三个连续的数最高位不同的数列长度为 \(2\times30\)
特判 \(n>60\) 时输出 \(1\) 即可通过本题。

#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 70

using namespace std;
int n, ans = N, a[N];

int read() {
  int s = 0, f = 0; char ch = getchar();
  while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
  while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
  return f ? -s : s;
}

int main() {
  n = read();
  if (n > 60) {
    printf("1\n");
    return 0; 
  }
  for (int i = 1; i <= n; ++ i) 
    a[i] = a[i - 1] ^ read(); 
  for (int l = 1; l < n - 1; ++ l) 
    for (int r = l; r < n; ++ r) 
      for (int k = r + 1; k <= n; ++ k) 
        if ((a[r] ^ a[l - 1]) > (a[k] ^ a[r])) 
          ans = min(ans, (r - l) + (k - r - 1));
  printf("%d\n", (ans == N) ? -1 : ans);
  return 0;
}

New Game Plus!

咕咕咕~~

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 500010

using namespace std;
const ll inf = 1e18;
int n, k, a[N];
ll ans = -inf, suml, sumr, sum[N], val[N];

int read() {
  int s = 0, f = 0; char ch = getchar();
  while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
  while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
  return f ? -s : s;
}

int main() {
  n = read(), k = read() + 1;
  for (int i = 1; i <= n; i++) a[i] = read();
  sort(a + 1, a + n + 1);
  for (int i = n; i >= 1; i--) sumr += 1ll * (i - 1) * a[i], sum[i] = sum[i + 1] + a[i];
  for (int i = 1, j = 1, lth = 0; i <= n; i++, j++) {
    if (j == k + 1) j = 1, lth++;
    ans = max(ans, suml + 1ll * lth * sum[i] + sumr);
    suml -= val[j];
    val[j] += 1ll * lth * a[i];
    suml += val[j];
    sumr -= sum[i + 1];
  }
  printf("%lld\n", ans);
  return 0;
}

鸣谢
Luckyblock


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM