給你乙個圖,讓你選擇權值和最小的邊,使得\(1\)和\(n\),\(2\)和\(n-1\),……,\(k\)和\(n-k+1\)聯通。
\(k\leq 4\)
一看到這題就覺得特別神仙……
然後去思考網路流……
搞出了乙個最小割,後來發現這是錯的……
匆匆打了個表,獲得了這題的十分之一的分數。
其實這題有水法,許多人是全排列+\(spfa\),跑了一遍之後將路過的邊清\(0\),繼續跑。這樣貪心顯然是錯的,反例也有,但是極其水的資料居然給了他們\(100\)分!
正解是dp。
題解中有個叫做\(stenir \ tree\)的東西,感覺似乎很強大。當然我不懂,我只會dp。
現在我們是要求出乙個最小生成森林,使得一些點對聯通。
考慮一棵樹。顯然,樹的葉子節點一定是要求聯通的節點(反過來倒不一定)。
於是我們就試著dp……
設\(f_\)表示當前這棵樹的根節點為\(i\),並且\(s\)集合中的所有點連在了一起的最小代價
轉移的時候就是兩棵樹的根節點連在一起,也就是\(f_+w(i,j)+f_\to f_\)
\(s'\)是\(s\)的子集。(列舉\(s\)和\(s'\)的時間複雜度是\(3^k\)的,\(k\)表示位數,具體實現比較巧妙,見**)
然後這道題就差不多完了。注意,轉移的時候一般是\(s\)從低到高轉移,但也會向\(s\)相等的狀態轉移,這就意味著會有後效性。所以,對於同層的轉移,我們特殊地用最短路演算法來處理。
using namespace std;
#include #include #include #include inline void update(int &a,int b)
#define n 10010
#define m 10010
int n,m,k;
struct edge e[m*2];
int ne;
edge *last[n];
inline void link(int u,int v,int len);
last[u]=e+ne++;
}int f[256][n],*dis;
struct node h[1000001];
int nh;
inline bool cmph(const node &son,const node &fa)
int mn[256],ans[256];
inline bool ok(int s)
int main()
memset(f,63,sizeof f);
for (int i=1;i<=k;++i)
f[1update(f[s][i],f[s1][i]+ei->len+f[s-s1][ei->to]);
dis=f[s];
nh=0;
for (int i=1;i<=n;++i)
h[nh++]=;
while (nh);
push_heap(h,h+nh,cmph);
}} mn[s]=int_max;
for (int i=1;i<=n;++i)
update(mn[s],dis[i]);
} memset(ans,63,sizeof ans);
ans[0]=0;
for (int s=1;s<1<
不是什麼題都能用網路流做的……
dp也能玩出各種花樣……
JZOJ5242 GDOI模擬 矩陣
給出乙個n m 的01 矩陣,求其中有多少個連續子矩陣,使得其面積大於等於k,且其中不包含1。非常經典的一道題目。首先我們很容易知道n 3的方法。那麼我們來優化一下。我們先求出f i j 表示從 i,j 向右連續1的數量。然後把這些從大到小的插入 桶排一下 然後如果上面或下面已經有了就合併,然後算出...
JZOJ5242 GDOI2018模擬8 8 矩陣
description 給出乙個n m 的01 矩陣,求其中有多少個連續子矩陣,使得其面積大於等於k,且其中不包含1。input 第一行為用空格隔開的三個整數n,m,k。分別表示矩陣的行數,列數和子矩陣的最小面積。接下來的n 行每行為用空格隔開的m 個整數,為題目中給出的矩陣。output 輸出一行...
JZOJ5233 GDOI模擬 概率博弈
小a和小b在玩遊戲。這個遊戲是這樣的 有一棵n個點的以1為根的有根樹,葉子有權值。假設有m個葉子,那麼樹上每個葉子的權值序列就是乙個1 m 的排列。一開始在1號點有一顆棋子。兩人輪流將這顆棋子移向其當前位置的乙個兒子。假如棋子到達葉子,遊戲結束,最終獲得的權值為所在葉子對應權值。小a希望最後的權值盡...