NOI2019 序列 題解

2022-03-10 20:52:41 字數 2605 閱讀 3405

同步賽當場降智了,認為貪心是假的。。。。然後。。。。就寫了個暴力。。。。

開題一看,這不是模擬費用流嗎?

然而這個費用流並不顯然。。。。所以我當時放棄了t3部分分沒想到。

當然也希望這個題解能讓大家懂得什麼是真正的模擬費用流

大概是這麼一張圖……

正確性嘛……就是如果選下標不同的一對數的話必須走\(c -> d\) 這條路徑

那麼就保證了下標不同的數的對數會\(<= k - l\),那麼相同的就至少有\(l\)對了。

然後你按上述方法建圖,寫個費用流就可以拿到\(n = 150\)或者\(n = 2000\)的分了。

考慮一點一點的增加流量。

如果弧\(cd\)沒有流滿,我們就流弧\(cd\),因為它的選擇最「自由」,得到的答案也最優。

怎麼流最優呢?當然是當前沒有被選中的數中,a/b各取乙個max

當然如果我們選的數中有下標相等的,就不用佔據弧cd的流量了,這個需要注意。

在弧\(cd\)流滿之後,我們考慮增加其他弧的流量,也就是要組成新的一對下標相等的數

首先我們可以直接找乙個ab都沒被選過的下標,選出乙個\(a_i+b_i\) 最大的,反映到圖上就是把 \(s->a_i ->b_i ->t\) 流一遍

我們還可以給乙個已經選中的\(a\)找乙個\(b\)和它配對,然後你會發現這會使得\(c\)少一點流量,所以我們要給\(c\)一點流量,不然就不滿足流量平衡了

所以我們還得再找乙個最大的沒選過的\(a\)……

同樣的我也可以給乙個沒配過對的\(b\)配對,再補乙個最大的\(b\)上去……

反映到圖上,就是把一條\(a_i->c\)的流量撤回,改為從\(a_i->b_i->t\)

然後換乙個\(a_j\)補上,流一下\(s - >a_j - >c\)這條邊。

過程中如果發現弧cd可以不流滿,比如上述配對的過程中如果配出了兩對的話,我們就在剩下的a和b中分別選取乙個最大值,保證cd流滿。

這個就是一些人的貪心……在此處orz@_rqy提供的貪心思路……

不過我把它用費用流的角度解釋的話……它就是模擬費用流呀!

所以這個貪心(模擬費用流)是正確的!

然後我們發現我們只要求乙個最大值……用堆維護就可以了……

(**行數有點多,勿噴)

**裡有詳細注釋~~~

// f1,f2表示可以用來做配對操作的堆,h1,h2表示a、b兩個陣列中剩餘的數

// h3存的是a、b都沒選的那些i(也是堆)

#include #define ll long long

using namespace std;

inline int read()

inline void write(ll x)

inline void writeln(ll x)

const int n = 1000050;

ll ans;

int t,n,l,k,a[n],b[n],s[n]; // 0 -> () 1 -> (a) 2 -> (b) 3 -> (ab)

int id[n];

inline bool cmpa(int x,int y)

inline bool cmpb(int x,int y)

inline void work(int m)

struct nodea }tmp1;

struct nodeb }tmp2;

struct nodeab }t***;

priority_queueh1,f1;

priority_queueh2,f2;

priority_queueh3;

int main()

else if (s[i] == 1) tmp2.id = i,h2.push(tmp2),f2.push(tmp2);

else if (s[i] == 2) tmp1.id = i,h1.push(tmp1),f1.push(tmp1);

else ++now;

//a、b都選了的,我會計到now中去,now表示cd弧剩餘的流量。

} while (l--)

continue;

}v1 = v2 = v3 = c1 = c2 = 0;

if (!f2.empty())

if (!f1.empty())

if (!h3.empty()) //選一對a+b

vmx = max(v1,max(v2,v3));

ans += vmx;

if (v1 == v2 && v1 == vmx)

else

continue;

}if (v1 == vmx)

if (v2 == vmx)

if (v3 == vmx)

} writeln(ans);

} return 0;

}

NOI2019 序列(模擬費用流)

有兩個長度為n的序列,要求從每個序列中選k個,並且滿足至少有l個位置都被選,問總和最大是多少。1 leq l leq k leq n leq 2 10 5 首先,記錄當前考慮到的位置i,第乙個選的數量a,第二個選的數量b,都被選的數量c,可以做到 o n 4 卡常後能過 n leq 150 有40分...

NOI2019 序列(模擬費用流)

有兩個長度為n的序列,要求從每個序列中選k個,並且滿足至少有l個位置都被選,問總和最大是多少。1 leq l leq k leq n leq 2 10 5 首先,記錄當前考慮到的位置i,第乙個選的數量a,第二個選的數量b,都被選的數量c,可以做到 o n 4 卡常後能過 n leq 150 有40分...

NOI2019 序列 貪心,模擬費用流

傳送門 首先你需要知道網路流的建圖方法,偷一張圖 我開始沒有想到怎麼限制 l 個相同,我們何不先選出 k 對,然後把 k 對拆開調整兩邊的最 擇 新建兩個點 c,d 來給兩邊調整的空間 我們可以模擬這個網路流的運作過程 類似某些貪心的題,用堆來維護最大之類的 我們可以記錄 cd 可以通過的流量 fl...