一棵\(n(n\le10^5)\)個結點的樹,在一些點上安裝\(k(k\le\min(n,100))\)個裝置。每個裝置可以控制所有與安裝位置相鄰的結點(不包括本身)。每個點可以安裝至多乙個裝置。問有多少種方案恰好用完\(k\)個裝置,使得所有的結點都被控制。
樹形dp。\(f[i][j][0/1][0/1]\)表示以\(i\)為根的子樹內安裝了\(j\)個裝置,\(i\)本身是否安裝,\(i\)是否被控制。手動討論轉移:
f[x][j+k][0][0]+=f[y][k][0][1]*g[j][0][0]
f[x][j+k][0][1]+=f[y][k][0][1]*g[j][0][1]
f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][1]
f[x][j+k][0][1]+=f[y][k][1][1]*g[j][0][0]
f[x][j+k][1][0]+=f[y][k][0][0]*g[j][1][0]
f[x][j+k][1][0]+=f[y][k][0][1]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][0]
f[x][j+k][1][1]+=f[y][k][0][0]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][0][1]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][1][0]*g[j][1][1]
f[x][j+k][1][1]+=f[y][k][1][1]*g[j][1][1]
需要卡常數和記憶體。
#include#include#includetypedef long long int64;
inline int getint()
const int n=1e5+1,m=101,mod=1e9+7;
int m,size[n],f[n][m][2][2],g[m][2][2],h[n];
struct edge ;
edge e[n<<1];
inline void add_edge(const int &u,const int &v) ;h[u]=h[0];
e[++h[0]]=(edge);h[v]=h[0];
}void dfs(const int &x,const int &par)
for(register int j=std::min(size[x],m);~j;j--)
} size[x]+=size[y]; }}
int main()
dfs(1,0);
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 潛入行動
題目鏈結 參考題解 注意題面 在當前節點設定監聽裝置不能監聽到節點本身。那麼節點能否被覆蓋和節點是否設定監聽裝置需要分開設。設 f 表示以第 i 個節點為根的子樹,除了 i 以外的節點都已經被覆蓋,i 號節點有沒有設定監聽裝置 有沒有被覆蓋的方案數。轉移方程 f sum f f f sum f f ...
JSOI2018 潛入行動
一道思路不難但是寫起來很麻煩的樹形揹包 我們發現每個節點有很多資訊需要保留 所以就暴力的設 f u j 0 1 0 1 表示點u的子樹分配了j個監察器,點u有沒有被控制,點u放沒放監察器 然後就分四種情況暴力討論就好了 注意揹包的時候要卡常數 include include include incl...