vijos 1770 大內密探(樹形dp 計數)

2021-09-06 19:07:50 字數 3135 閱讀 6541

不重不漏地設計狀態才能正確的計數qaq

雖然可能最優化是正確的,但是不能保證狀態不相交就是作死。。。。

之前設的狀態錯了。。。

應該設f[i][0]表示i點不取且至少有乙個兒子取,且保證i點被覆蓋

f[i][1]表示i點取兒子任意,且保證i點被覆蓋

f[i][2]表示i點不取且i點的兒子也不取,保證i點不被覆蓋!(即留給父親覆蓋)

f[i][2]表示i點不取且兒子也不取。並不是表示i點不取兒子任意!!!!!!!!!!要不然這樣會出現交的情況!假設使用後者,那麼就會產生和f[i][0]一樣的狀態!!!!!!

然後我們分別計數

g[i][0]表示f[i][0]的方案數,g[i][1]表示f[i][1]的方案數,g[i][2]表示f[i][2]的方案數,那麼有初始化

g[i][0]=0 當i沒有兒子時

而轉移f[i][1]和f[i][2]很簡單,即

f[i][1]=sigma (j是i兒子) }

f[i][2]=sigma

方案的話加法乘法原理上。。。

f[i][0]轉移非常麻煩(因為還要顧及到g[i][0],要做到不重不漏!)

首先我們知道,至少要有乙個兒子選中狀態才能轉移。

如果不小心,很容易得到

f[i][0]=min} (j和k均為i兒子且j!=k) }

這樣雖然可以用技巧實現o(n)轉移,但是方案卻不能夠得到!

比如i有2和3這兩個兒子,f[3][0]=5, f[3][1]=3, f[2][0]=6, f[2][1]=3;那麼轉移的時候,兩次決策都是f[2][1]+f[3][1]或f[3][1]+f[2][1]!!!!!這樣顯然不能計數。。重合了。。

所以我之前就這樣sb了。。

那麼我們考慮如何去重?我們分析得到,我們列舉要取的兒子時,之前列舉過的全部給取f[k][0],沒有取過的任意!!!!這樣就不會重!

那麼問題就好解決了,我們在列舉兒子時,維護乙個字首和f[k][0],k是已經列舉過的,然後再維護乙個字尾和,表示sum},l是未列舉過的

計數的方法相同,那麼問題就解決了orz

#include #include #include #include #include #include #include #include #include using namespace std;

typedef long long ll;

#define pii pair#define mkpii make_pair#define pdi pair#define mkpdi make_pair#define pli pair#define mkpli make_pair#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define cc(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define error(x) (!(x)?puts("error"):0)

#define printarr2(a, b, c) for1(_, 1, b)

#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl

inline const int getint()

inline const int max(const int &a, const int &b)

inline const int min(const int &a, const int &b) e[n<<1];

ll mul(ll a, ll b)

ll plus(ll a, ll b)

void add(int u, int v)

void dfs(int x, int fa)

f[x][1]=t1;

f[x][2]=t2;

d[x][1]=s1;

d[x][2]=s2;

int sz=0;

rdm(x, i) if(e[i].to!=fa) st[++sz]=e[i].to;

r[sz+1]=0; sumr[sz+1]=1; suml=1; l=0;

for3(i, sz, 1)

f[x][0]=n;

for1(i, 1, sz) {

if(l+f[st[i]][1]+r[i+1]大內密探,負責秘密保護皇上,還有保護皇宮內外一切產業。——大內密探零零七

在古老的皇宮中,有n個房間以及n-1條雙向通道,每條通道連線著兩個不同的房間,所有的房間都能互相到達。皇宮中有許多的寶物,所以需要若干個大內密探來守護。乙個房間被守護當切僅當該房間內有一名大內密探或者與該房間直接相鄰的房間內有大內密探。

現在身為大內密探零零七的你想知道要把整個皇宮守護好至少需要多少名大內密探以及有多少種安排密探的方案。兩種方案不同當且僅當某個房間在一種方案有密探而在另乙個方案內沒有密探。

第一行乙個正整數n.(1<=n<=100000)

後面n-1行,每行兩個正整數a和b,表示房間a和房間b之間有一條無向通道。

房間的編號從1到n

第一行輸出正整數k,表示最少安排的大內密探。

第二行輸出整數s,表示有多少種方案安排最少的密探,由於結果可能較大,請輸出方案數mod 1000000007的餘數。

7

2 13 1

4 25 1

6 27 6

3

4

每個測試點1s

30%保證:n <= 10

70%保證:n <= 1000

100%保證:n <= 100000

177 單詞替換

題目描述 你需要輸出替換之後的句子。示例 1 輸入 dict 詞典 cat bat rat sentence 句子 the cattle was rattled by the battery 輸出 the cat was rat by the bat 注 輸入只包含小寫字母。1 字典單詞數 1000...

careercup 中等難度 17 7

17.7 給定乙個整數,列印該整數的英文描述 例如 one thousand,two hundred thirty four 解法 舉個例子,在轉換19 323 984時,我們可以考慮分段處理,沒三位轉換一次,並在適當的地方插入 thousand 千 和 million 百萬 也即,convert ...

177 有限制的素數

輸入檔案 qprime.in 輸出檔案 qprime.out 簡單對比 時間限制 1 s 記憶體限制 128 mb farmer john 開始給奶牛們標記上素數的牌子,貝茜注意到了這一切,她對各種數的牌子很好奇。請幫助貝茜算出從a到b 1 a b 4,000,000 b a 1,000,000 b...