upd : \(cnt_i\) 代表值為 \(i\) 的個數
我們可以暴力列舉眾數 \(k\)
把等於 \(k\) 的賦值成 1 , 不等於 \(k\) 的賦值成 -1
這樣原序列就變成了一段折線
我們把他剖開一段一段來分析
這些藍線的左右端點分別為, 乙個值為眾數的數的位置, 和它下乙個值為眾數的數的位置的前乙個位置
為了方便, 我們定義 \(0\) , \(n + 1\) 這兩個位置上的數可以當做任意乙個位置
我們對於一條藍線扯出來單獨分析
設 \(sum_i\) 為折線在 \(i\) 這個點的值
只要我們找到兩個點滿足 \(i > j\) , 並且滿足 \(sum_i > sum_j\) , 就有序列在 \([j + 1, i]\) 上的變化大於 0 , 也就是說是滿足區間眾數大於區間長度一半的
設它的值域為 \([l, r]\) , 暴力做法是這樣的
考慮優化這個過程
\[\displaystyle
\begin
ans &= \sum_^r\sum_^cnt_i\\
&= (r - l + 1) \sum_^cnt_i + \sum_^(r - i)*cnt_i\\
&= (r - l + 1) \sum_^cnt_i + r * \sum_ ^ cnt_i - \sum_ ^ i * cnt_i
\end
\]然後像上面那樣每乙個藍色的線都這麼分析
對於乙個眾數 \(k\) 它的複雜度為 \(o(mlogn)\) , \(m\) 為 \(a\) 中等於 \(k\) 的數的個數
所以總的複雜度就是 \(o(nlogn)\)
#include #include #include #include #include typedef long long ll;
const int n = 500005;
using namespace std;
int n, m, a[n];
struct tree t[n << 4];
vector vec[n];
ll ans;
template < typename t >
inline t read()
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}void update(int p)
void pushdown(int p, int l, int r)
}void modify(int p, int l, int r, int ql, int qr, int k)
pushdown(p, l, r);
int mid = (l + r) >> 1;
if(ql <= mid) modify(p << 1, l, mid, ql, qr, k);
if(mid < qr) modify(p << 1 | 1, mid + 1, r, ql, qr, k);
update(p);
}ll query(int p, int l, int r, int ql, int qr, int op, int opt = 1)
int main()
for(int i = 0; i < n; i++)
vec[i].push_back(n + 1);
for(int sz, st, ed, i = 0; i < n; i++)
st = 0;
for(int j = 0; j < sz; j++)
}printf("%lld\n", ans);
return 0;
}
清華月賽 Yazid的新生舞會題解
考慮列舉所有區間,然後求其眾數及出現次數,並判斷是否超過區間總長的一半,統計答案即可。時間複雜度o n3 考慮先列舉區間的左端點 l 再從左到右列舉右端點 r並用陣列維護每個數的出現次數,同時使用變數維護當前眾數 眾數的出現次數。不難發現,當右端點向右移動時,這些資訊都是非常方便維護的。於是我們便可...
題解 P4058 Code 1 木材
這什麼題啊,不就是個二分答案我從65到100都經歷了一遍 瞬間氣哭 題目理解起來不難的,大意就懶得寫了。一眼二分答案。此題屬於在形如 的序列中查詢第乙個 1 的題型。演算法流程 初始化 l 0,r inf r 盡可能大 如果 l r 停止迴圈。計算中點 mid left lfloor dfrac r...
2020HAUT 暑假新生訓練1 題解
題意 在二維座標系內,給你乙個起點,再給你乙個終點,外加乙個按週期迴圈的干擾因素 風,問你多少天能到達終點。簡單說,每天可以移動乙個單位,且要風力方向移動乙個單位。題解 統計在乙個週期內每天因風力移動的距離 分為兩個方向 和 可以自由移動的次數,當自由移動的次數不小於風力影響後的位置到終點的距離時即...