P10280 [USACO24OPEN] Cowreography G 題解

下蛋爷發表於2024-07-23

Description

奶牛們組了一支舞蹈隊,Farmer John 是她們的編舞!舞蹈隊最新而最精彩的舞蹈有 \(N\) 頭奶牛(\(2\le N\le 10^6\))排成一行。舞蹈中的每次動作都涉及兩頭奶牛,至多相距 \(K\) 個位置(\(1\le K < N\)),優雅地跳起並降落在對方的位置上。

隊伍中有兩種奶牛——更賽牛(Guernsey)和荷斯坦牛(Holstein)。因此,Farmer John 將這一舞蹈記錄為一系列長為 \(N\)01 字串,其中 0 代表更賽牛,1 代表荷斯坦牛,整個字串表示奶牛在這一行中是如何排列的。

不幸的是,Farmer Nhoj(對手團隊的編舞)蓄意破壞了這一舞蹈,並清除了除第一個和最後一個 01 字串之外的所有內容!由於一場大型比賽即將開始,Farmer John 必須抓緊每一秒重建這一舞蹈。

給定這兩個 01 字串,幫助 Farmer John 求出舞蹈中的最小動作數量!

Solution

考慮交換一對 \(i,j(a_i\neq a_j)\) 所用的代價,結論是 \(\left\lceil\frac{|i-j|}{k}\right\rceil\)

證明就考慮數學歸納法,不妨設 \(i<j\) 且長度小於 \(j-i\) 的已經滿足結論,容易發現對於 \(j-i\leq k\)\((i,j)\) 一定滿足條件。

對於 \(i<s<j\),如果 \(a_i=a_s\) 則先交換 \((j,s)\) 再交換 \((i,s)\),否則先交換 \((i,s)\) 在交換 \((j,s)\),對應的代價為 \(\left\lceil\frac{s-i}{k}\right\rceil+\left\lceil\frac{j-s}{k}\right\rceil\),容易發現當 \(s\)\(i+k\) 時可以取到最小值,即為 \(\left\lceil\frac{|i-j|}{k}\right\rceil\)

有了這個結論就可發現這裡的交換一定是兩兩匹配,即在一張二分圖上匹配。

如果沒有取上整就從前往後掃,如果 \(a_i\neq b_i\) 就找到任意一個還沒匹配的 \(j\) 使得 \(a_i\neq a_j\) 匹配,容易發現這個一定是最小值。

如果有了取上整,感性理解可以發現這裡需要讓 \((i-j)\bmod k\) 的和儘可能小,所以只要把上面選任意一個匹配變為選使得 \((i-j)\bmod k\) 最小的 \(j\) 匹配即可。

時間複雜度:\(O(n\log n)\)

Code

#include <bits/stdc++.h>

// #define int int64_t

int n, k;
std::string a, b;

void dickdreamer() {
  std::cin >> n >> k >> a >> b;
  a = " " + a, b = " " + b;
  std::set<std::pair<int, int>> st[2];
  int64_t ans = 0;
  for (int i = 1; i <= n; ++i) {
    if (a[i] == b[i]) continue;
    int oa = a[i] - '0', ob = b[i] - '0';
    if (!st[ob].empty()) {
      auto it = st[ob].lower_bound({i % k, 0});
      if (it == st[ob].end()) it = st[ob].begin();
      ans += (i - it->second + k - 1) / k;
      st[ob].erase(it);
    } else {
      st[oa].emplace(i % k, i);
    }
  }
  std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

相關文章