JSOI2018 潛入行動 樹形揹包

2021-10-09 13:34:06 字數 2297 閱讀 3061

題意:

外星人的母艦可以看成是一棵 n 個節點、 n−1 條邊的無向樹,樹上的節點用 1,2,⋯,n 編號。jyy 的**已經裝備了**模組,可以在外星人母艦中不受限制地活動,可以神不知鬼不覺地在節點上安裝監聽裝置。

如果在節點 u 上安裝監聽裝置,則 jyy 能夠監聽與 u 直接相鄰所有的節點的通訊。換言之,如果在節點 u 安裝監聽裝置,則對於樹中每一條邊 (u,v) ,節點 v 都會被監聽。

特別注意放置在節點 u 的監聽裝置並不監聽 u 本身的通訊,這是 jyy 特別為了防止外星人察覺部署的戰術。

jyy 的**一共攜帶了 k 個監聽裝置,現在 jyy 想知道,有多少種不同的放置監聽裝置的方法,能夠使得母艦上所有節點的通訊都被監聽?為了避免浪費,每個節點至多只能安裝乙個監聽裝置,且監聽裝置必須被用完。\(n\leq 100000 ,k\leq 100\)。

顯然是樹形揹包dp。

但是,狀態比較難設計。如果u沒有被監視,則u的子節點必須至少有乙個選。所以要加一維表示選不選。

而如果u被監視了,則u的子節點可以都不選。所以要加一維表示u是否被監視。

這樣就好理解了。

f1[a+b][0]=(f1[a+b][0]+1ll*x0[a][0]*dp[v[i]][b][0][0])%md;

f1[a+b][1]=(f1[a+b][1]+1ll*x0[a][0]*dp[v[i]][b][0][1]+1ll*x0[a][1]*(dp[v[i]][b][0][0]+dp[v[i]][b][0][1]))%md;

f2[a+b][0]=(f2[a+b][0]+1ll*x1[a][0]*dp[v[i]][b][1][0])%md;

f2[a+b][1]=(f2[a+b][1]+1ll*x1[a][0]*dp[v[i]][b][1][1]+1ll*x1[a][1]*(dp[v[i]][b][1][1]+dp[v[i]][b][1][0]))%md;

關鍵是複雜度。

首先,常規樹形揹包是\(o(n^2)\)的。

就是每對點會在lca處貢獻複雜度。

但是,這個演算法,最初覺得是\(o(nk^2)\)的,實際上是\(o(nk)\)的。

證明:根據正常樹形揹包的複雜度\(o(n^2)\),小於等於k的最多產生\(n/k*k^2\)的複雜度。

大於k與大於k的合併一次,被合併的就增加k,最多n/k次,最多產生\(n/k*k^2\)的複雜度。

大於k的與小於等於k的合併時,每個小於等於k的最多被合併一次,所以是\(n*s_1+n*s_2+...+n*s_m\),也是\(nk\)。

還有一種理解,不知道對不對:

把樹按照dfs序變為序列。

然後,在子樹中列舉取x個,可以理解為取dfs序的前(後)x個。

而合併時,認為一棵子樹取後x個,另一棵取前y個。\((x+y\leq k)\)。這可以合併為長x+y的區間。

這其實就是長度不大於k的子串,最多有nk個。

但是,因為有取0個的情況,所以實際做題時,大約有2的常數。但那個常數就忽略了可以。

#include #define min(a, b)(a < b ? a: b)

#define md 1000000007

inline int read()

int dp[100002][102][2][2],f1[102][2],f2[102][2];

int x0[102][2],x1[102][2],sz[100002];

int fr[100002],ne[200002],v[200002],bs = 0,k;

void addb(int a, int b)

void dfs(int u, int fu)

} for (int i = 0; i <= min(k, si); i++) x0[i][0] = x1[i][0] = 0;

x0[0][0] = x1[0][0] = 1;

si = 0;

for (int i = fr[u]; i != -1; i = ne[i])

} si += rt;

for (int a = 0; a <= min(si, k); a++)

} for (int a = 0; a <= min(si, k); a++)

for (int a = 1; a <= min(si + 1, k); a++)

sz[u] = si + 1;

}int main()

dfs(1, 0);

printf("%d", (dp[1][k][0][0] + dp[1][k][0][1]) % md);

return 0;

}

JSOI2018 潛入行動

題目 我好菜啊,嚶嚶嚶 原來本地訪問陣列負下標不會報 re 或者 wa 甚至能跑出正解啊 這道題還是非常呆的 我們發現 k 很小,於是斷定這是乙個樹上揹包 發現在乙個點上安裝控制器並不能控制這個點,可能需要到父親那邊才能控制這個點,於是我們設 dp i j 0 1 0 1 表示在以 i 為根的子樹裡...

JSOI2018 潛入行動

一棵 n n le10 5 個結點的樹,在一些點上安裝 k k le min n,100 個裝置。每個裝置可以控制所有與安裝位置相鄰的結點 不包括本身 每個點可以安裝至多乙個裝置。問有多少種方案恰好用完 k 個裝置,使得所有的結點都被控制。樹形dp。f i j 0 1 0 1 表示以 i 為根的子樹...

JSOI2018 潛入行動

題目鏈結 參考題解 注意題面 在當前節點設定監聽裝置不能監聽到節點本身。那麼節點能否被覆蓋和節點是否設定監聽裝置需要分開設。設 f 表示以第 i 個節點為根的子樹,除了 i 以外的節點都已經被覆蓋,i 號節點有沒有設定監聽裝置 有沒有被覆蓋的方案數。轉移方程 f sum f f f sum f f ...