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