直接樹形dp設\(f[i][j][0/1][0/1]\)表示\(i\)子樹,選了\(j\)個,\(i被覆蓋了嗎\),\(選了i嗎\)
複雜度是\(o(n*k^2)\)。
加上子樹大小優化,複雜度降為\(o(nk)\),還有其它優化:
考慮度數為1的點,與它唯一相鄰的點必須要選。
把必須要選的點找出來,如果\(>k\),則直接輸出0。
進行了這個優化後,發現要合併的\(>1\)的子樹不超過\(k\)個。
所以複雜度降為\(o(nk+k^3)\)
code:
#include#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 1e9 + 7;
const int n = 1e5 + 5;
int n, k, x, y, r[n];
vectore[n];
#define pb push_back
#define si size()
int fa[n], siz[n];
int f[n][101][2][2];
ll g[101][2][2];
void dg(int x)
} siz[x] = min(k, siz[x] + siz[y]);
fo(i, 0, siz[x]) fo(j, 0, 1) fo(t, 0, 1)
f[x][i][j][t] = g[i][j][t] % mo; }}
int bz[n];
int main()
int cnt = 0;
fo(i, 1, n) if(r[i] == 1)
fo(i, 1, n) cnt += bz[i];
if(cnt > k)
dg(1);
ll ans = ((ll) f[1][k][1][0] + f[1][k][1][1]) % mo;
pp("%lld\n", ans);
}
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 ...