HNOI AHOI2018 排列(貪心)

2022-07-05 17:30:13 字數 1409 閱讀 3588

題目鏈結

好像之前模擬賽考過原題,不過這個題的題意是真的看不懂,還有題解區都說省選出原題,原來省選都會出原題的呀,我吐了。

給陣列 \(a\)(\(0 <= a_i <= n\)) 和 \(w\),它的乙個排列合法當且僅當對於 \(p[j] <= p[k]\),那麼不存在 \(a_ == p[k]\),定義該排列的價值為 \(\sum_^i*w_\),要求是價值最大化。

反正在沒有看題解之前我連題意都讀不懂,u1s1,這道省選題出的是真的爛啊,不過題中的套路還是不錯的。

我們可以把題意轉化為對於 \(a[i] = k\),那麼在 \(p\) 陣列裡 \(k\) 要放到 \(i\) 的前面,我們考慮建圖,對於這樣的情況我們 \(k->i\),即 \(k\) 連向 \(i\)。

圖如果是一棵基環樹,那麼本題無解,否則是一棵以 \(0\) 為根的樹,題目轉化為給定一棵樹,每個節點都有乙個價值,要求選乙個節點必須先選它的父親,求最大價值。

我們不難想到經典的套路題,取出當前 \(w\) 最小的點,如果它已經沒有父親了,那麼直接計算答案,否則把它和它的父親合併成乙個點,且新點的權值定義為它們權值的平均數,然後重複該過程,得到的便是答案。

對於為啥是權值的平均值,這個是可以推柿子的,因為每次合併相當於兩個序列合併,隨便推一下柿子就可以得到平均值的結論了。

其實這道題的實現方法還是挺值得研究的,主要是利用堆來實現,並且用並查集來維護聯通塊和最新的情況,方便即時排除堆中過時的元素,利用0號節點方便直接計算答案。

// by longdie 

#include #define ll long long

using namespace std;

const int n = 5e5 + 5;

ll ans, w[n];

int n, a[n], fa[n], siz[n];

struct node

node(int a, ll b, ll c)

friend bool operator < (const node &a, const node &b)

}; priority_queueq;

inline int find(int x)

inline void merge(int x, int y)

signed main()

for(register int i = 0; i <= n; ++i) fa[i] = i, siz[i] = 1;

for(register int i = 1; i <= n; ++i)

scanf("%lld", &w[i]), q.push(node(i, w[i], 1));

while(q.size())

cout << ans << '\n';

return 0;

}

題解 HNOI AHOI2018 毒瘤

題目傳送門 給出乙個 n 個點 m 條邊的無向圖,問有多少個點集滿足點集中任意兩點均不存在邊相連。n le 10 5,m n le 10 答案對 998244353 取模。妙啊!首先我們從樹的形態開始考慮,你發現答案其實就是獨立集的個數,具體來說我們可以設 f 表示 u 點選或不選的方案數,可以得到...

HNOI AHOI2018 尋寶遊戲

hnoi ahoi2018 尋寶遊戲 思維好題。將每一位領出來,組成 m 個長度為 n 的二進位制數。考慮將操作轉化為 01 序列,lor to0,land to1 觀察之後發現要使得第 j 位運算結果是 1 則最後乙個 lor1 操作的位置一定要在 land0 後面。轉化一下就是就要求 x gt ...

洛谷 HNOI AHOI2018 道路

初見安 這裡是傳送門 洛谷p4438 道路 題目乍一看很複雜,其實挺簡單的 就是一棵有根的滿二叉樹,要從每個葉子節點出發到根節點,每條路有個性質,公路or鐵路,現在要選n 1條道路翻新,滿足題目所述的條件。看n的範圍明顯是不能暴力列舉的。但是我們可以抓住一點 樹的深度不超過40。也就是說每個節點到根...