Algoogle

Algorithm for Programming Contest

Typical DP Contest P - うなぎ

Category: TDPC Tag: dp

P - うなぎ

問題概要


解法


適当に根をつけて木DPします.
dp[i][j][k] := 頂点i以下の部分木でj本のパスを書いて頂点iの次数がkのときの場合の数

更新は頂点iに子を順に加えていく感じのDPをする.
dp2[l][m][n] := l番目の子まででi以下の部分木にj本のパスを書いて頂点iの次数がnのときの場合の数

このdp2の更新は頂点iとその子に辺を加えるかどうかを全てのパターンでやればよい.
次数0同士つなぐんだったらパスの本数が1増えるとか全部やる.

コード


(P.cpp) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <bits/stdc++.h>
using namespace std;
#define repi(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repi(i,0,n)

const int mod = 1e9+7;
inline void add(int &x, int y) {x+=y;if(x>=mod)x-=mod;}
inline int mul(int x, int y) {return 1LL*x*y%mod;}

int N, K, dp[1024][64][4], dp2[1024][64][4];
vector<int> g[1024];

void dfs(int v, int u) {
    vector<int> cs;
    for(auto &e: g[v]) if(e != u) {
            cs.push_back(e);
            dfs(e,v);
        }
    memset(dp2,0,sizeof(dp2));
    dp2[0][0][0] = 1;
    rep(i,cs.size()) rep(j,K+1) rep(k,3) rep(l,K+1) rep(m,3) {
        int val = mul(dp2[i][j][k], dp[cs[i]][l][m]);
        if(!val or j+l > K+1) continue;
        add(dp2[i+1][j+l][k], val);
        if(k == 0) {
            if(m == 0) add(dp2[i+1][j+l+1][1], val);
            if(m == 1) add(dp2[i+1][j+l][1], val);
        }
        if(k == 1) {
            if(m == 0) add(dp2[i+1][j+l][2], val);
            if(m == 1) add(dp2[i+1][j+l-1][2], val);
        }
    }
    memcpy(dp[v], dp2[cs.size()], sizeof(dp[v]));
}

int solve() {
    dfs(0,-1);
    return (1LL*dp[0][K][0]+dp[0][K][1]+dp[0][K][2])%mod;
}

void input() {
    cin >> N >> K;
    int a, b;
    rep(i,N-1) {
        cin >> a >> b;
        a--; b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
}

int main() {
    cin.tie(0);
    ios_base::sync_with_stdio(0);
    cout << fixed << setprecision(12);
    input();
    cout << solve() << endl;
    return 0;
}

Comments