JSOI2018 潛入行動

2022-09-28 11:39:07 字數 1456 閱讀 5693

題意

link

在 \(n(\leq 10^5)\) 個點選 \(k(\leq 100)\) 個點, 被選出的點周圍的點不包括自己都會被覆蓋,求所有點都被覆蓋的方案數。

樹形揹包

其實就是簡單的樹形揹包,分類討論清楚就行了。

狀態\(f[u][k][1/0][1/0]\) 表示節點 \(u\), 已經選了 \(k\) 個點,現在 \(u\) 是否被覆蓋,\(u\) 是否被選, 並且除了根外所有節點都被覆蓋。

初始狀態

對於乙個點的樹,\(f[u][0][0][0] = f[u][1][0][1] = 1\)。

轉移考慮兩個樹合併,每個結點最開始是乙個點的樹, 以下的轉移都滿足狀態。

\(f[u][k][0][0] = f[u][i][0][0] * f[v][j][1][0]\)

\(f[u][k][0][1] = f[u][i][0][1] * (f[v][j][0][0] + f[v][j][1][0])\)

\(f[u][k][1][0] = f[u][i][1][0] * (f[v][j][1][0] + f[v][j][1][1]) + f[u][i][0][0] * f[v][j][1][1]\)

\(f[u][k][1][1] = f[u][i][0][1] * (f[v][j][0][1] + f[v][j][1][1]) + f[u][i][1][1] * (f[v][j][0][0] + f[v][j][0][1] + f[v][j][1][0] + f[v][j][0][1])\)

最後的答案即是 \(f[1][k][1][0] + f[1][k][1][1]\)

分析樹形揹包如果轉移的次數是 兩個樹的大小的乘積,那麼就有整體時間複雜度 \(o(nk)\)。

空間也是 \(o(nk)\)。

****是好久之前的,狀態後兩維是反過來的。

#include#define ll long long

using namespace std;

const int mod = 1000000007;

const int maxn = 100010;

int n, m;

int a[maxn];

struct edgee[maxn << 1];

int first[maxn];

void add(int u, int v)

int f[maxn][103][2][2], siz[maxn], tmp[210][2][2];

int add(int a, int b)

void dp(int u, int fa)

siz[u] += siz[v]; }}

int main()

dp(1, 1);

printf("%d\n", (f[1][m][0][1] + f[1][m][1][1]) % mod);

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 ...