首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Codeforces 558C Amr and Chemistry:位運算與公共前綴優化

     編輯:關於C++

問題描述

給定 n 個數 a_i。每次操作可將一個數 ×2 或 ÷2(向下取整)。求使所有數相等的最少操作總次數。n ≤ 10^5, a_i ≤ 10^5。

核心觀察:二進制公共前綴

操作 ×2 相當於二進制左移一位(補 0),÷2 相當於右移一位(捨去最低位)。因此,所有數最終能變成的值,必須是某個數通過右移若干位得到的前綴,再左移若干位得到的值。換句話說,目標值的二進制表示必須是所有 a_i 二進制表示的「公共前綴」加上任意後綴 0。

算法思路

  1. 對每個 a_i,枚舉其所有可能的「祖先值」(不斷右移直到 0),記錄到達每個祖先值所需的右移步數 down。
  2. 對每個祖先值 v,考慮將其作為目標值的「核心前綴」。所有數必須通過右移到達某個祖先 v_i,使得所有 v_i 相等(即同一 v),然後再左移若干步對齊。總步數 = Σ(down_i + up_i)。
  3. 枚舉所有可能的核心前綴 v(實際上只需枚舉第一個數的所有祖先),計算總步數,取最小值。

優化實現

用數組 cnt[v] 統計有多少數能到達 v,sum[v] 統計到達 v 的總右移步數。對每個 a_i,沿右移路徑更新 cnt 和 sum,同時記錄層級。最後枚舉 v,若 cnt[v]==n,則總步數 = sum[v] + n * level[v](其中 level[v] 為從 v 到目標值的左移步數,需進一步優化)。

代碼框架(關鍵邏輯)

const int MAXA = 200000;
int cnt[MAXA], sum[MAXA], level[MAXA];

for (int i=0;i>= 1; steps++;
    }
}
int ans = INF;
for (int v=0; v

更簡潔的做法:枚舉目標值

因 a_i ≤ 10^5,目標值不超過 2*10^5。對每個可能目標值 t,計算所有 a_i 到達 t 的最小步數:對每個 a_i,枚舉其右移路徑上的祖先 v,若 v 能通過左移到達 t(即 t % v == 0 且 t/v 為 2 的冪),則步數 = 右移步數 + 左移步數。取所有 a_i 的最小步數之和。總複雜度 O(n log A + A log A) 可行。

總結

CF 558C 巧妙利用二進制移位性質,將操作轉化為樹上最近公共祖先問題。關鍵在於識別「×2/÷2」對應「左移/右移」,並利用祖先鏈枚舉。此類位運算視角極具通用性,可應用於許多數值變換問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved