Problem:


Score : 900 points

Problem Statement

Let N be an even number.

There is a tree with N vertices.
The vertices are numbered 1, 2, ..., N.
For each i (1 \leq i \leq N - 1), the i-th edge connects Vertex x_i and y_i.

Snuke would like to decorate the tree with ribbons, as follows.

First, he will divide the N vertices into N / 2 pairs.
Here, each vertex must belong to exactly one pair.
Then, for each pair (u, v), put a ribbon through all the edges contained in the shortest path between u and v.

Snuke is trying to divide the vertices into pairs so that the following condition is satisfied: "for every edge, there is at least one ribbon going through it."
How many ways are there to divide the vertices into pairs, satisfying this condition?
Find the count modulo 10^9 + 7.
Here, two ways to divide the vertices into pairs are considered different when there is a pair that is contained in one of the two ways but not in the other.

Constraints

N is an even number.

2 \leq N \leq 5000

1 \leq x_i, y_i \leq N

The given graph is a tree.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_{N - 1} y_{N - 1}

Output

Print the number of the ways to divide the vertices into pairs, satisfying the condition, modulo 10^9 + 7.

Sample Input 1

4
1 2
2 3
3 4

Sample Output 1

2

There are three possible ways to divide the vertices into pairs, as shown below, and two satisfy the condition: the middle one and the right one.

Sample Input 2

4
1 2
1 3
1 4

Sample Output 2

3

There are three possible ways to divide the vertices into pairs, as shown below, and all of them satisfy the condition.

Sample Input 3

6
1 2
1 3
3 4
1 5
5 6

Sample Output 3

10

Sample Input 4

10
8 5
10 8
6 5
1 5
4 8
2 10
3 6
9 2
1 7

Sample Output 4

672



Sample input:
4
1 2
2 3
3 4


Sample output:
2

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 5001
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

import sys

sys.setrecursionlimit(10**4)
input=sys.stdin.buffer.readline

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]
def dfs(v,pv):
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        if nv!=pv:
            dfs(nv,v)
            merged=[0]*(sz[v]+sz[nv]+1)
            for i in range(sz[v]+1):
                for j in range(sz[nv]+1):
                    merged[i+j]=(merged[i+j]+dp[v][i]*dp[nv][j])%mod
            sz[v]+=sz[nv]
            dp[v] =merged
    for k in range(1,sz[v]+1):
        dp[v][0]=(dp[v][0]-(g1[k]*g2[k//2])%mod*((k+1)%2)*dp[v][k])%mod

dfs(0,-1)

print((-dp[0][0]*pow(inverse[2],N//2,mod))%mod)

Submission status: Time Limit Exceeded

Solution code:
def main():
    mod = 10**9+7 #出力の制限
    N = 5001
    g1 = [1, 1] # 元テーブル
    g2 = [1, 1] #逆元テーブル
    inverse = [0, 1] #逆元テーブル計算用テーブル
    
    for i in range( 2, N + 1 ):
        g1.append( ( g1[-1] * i ) % mod )
        inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
        g2.append( (g2[-1] * inverse[-1]) % mod )
    
    Pow=[pow(inverse[2],i,mod) for i in range(N+1)]
    
    def func(n):
        if n%2==0:
            return (-g1[n]*g2[n//2]*Pow[n//2])%mod
        else:
            return 0
    
    import sys
    
    sys.setrecursionlimit(10**4)
    input=sys.stdin.buffer.readline
    
    N=int(input())
    edge=[[] for i in range(N)]
    for i in range(N-1):
        x,y=map(int,input().split())
        edge[x-1].append(y-1)
        edge[y-1].append(x-1)


    dp=[[] for i in range(N)]
    sz=[0 for i in range(N)]

    def dfs(v,pv):
        sz[v]=1
        dp[v]=[0]*(sz[v]+1)
        dp[v][1]=1
        for nv in edge[v]:
            if nv!=pv:
                dfs(nv,v)
                merged=[0]*(sz[v]+sz[nv]+1)
                for i in range(sz[v]+1):
                    for j in range(sz[nv]+1):
                        merged[i+j] +=dp[v][i]*dp[nv][j]
                        merged[i+j]%=mod
                sz[v]+=sz[nv]
                dp[v] =merged
        dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod

    dfs(0,-1)

    print((-dp[0][0])%mod)

if __name__=="__main__":
    main()

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 5001
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

Pow=[pow(inverse[2],i,mod) for i in range(N+1)]

def func(n):
    if n%2==0:
        return (-g1[n]*g2[n//2]*Pow[n//2])%mod
    else:
        return 0

import sys

sys.setrecursionlimit(10**4)
input=sys.stdin.buffer.readline

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

def dfs(v,pv):
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        if nv!=pv:
            dfs(nv,v)
            merged=[0]*(sz[v]+sz[nv]+1)
            for i in range(sz[v]+1):
                for j in range(sz[nv]+1):
                    merged[i+j] +=dp[v][i]*dp[nv][j]
                    merged[i+j]%=mod
            sz[v]+=sz[nv]
            dp[v] =merged
    dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod

dfs(0,-1)

print((-dp[0][0])%mod)

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 2*10**5
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

Pow=[pow(inverse[2],i,mod) for i in range(N+1)]

def func(n):
    if n%2==0:
        return (-g1[n]*g2[n//2]*Pow[n//2])%mod
    else:
        return 0

import sys

sys.setrecursionlimit(10**4)

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

def dfs(v,pv):
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        if nv!=pv:
            dfs(nv,v)
            merged=[0]*(sz[v]+sz[nv]+1)
            for i in range(sz[v]+1):
                for j in range(sz[nv]+1):
                    merged[i+j] +=dp[v][i]*dp[nv][j]
                    merged[i+j]%=mod
            sz[v]+=sz[nv]
            dp[v] =merged
    dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod

dfs(0,-1)

print((-dp[0][0])%mod)

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 2*10**5
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

def func(n):
    if n%2==0:
        return (-g1[n]*g2[n//2]*pow(inverse[2],n//2,mod))%mod
    else:
        return 0

import sys

sys.setrecursionlimit(10**5)

N=int(input())
edge=[[] for i in range(N)]
parent=[0]*N
deg=[1]*N
deg[0]=0
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


def prv(v,pv):
    for nv in edge[v]:
        if nv!=pv:
            parent[nv]=v
            prv(nv,v)

prv(0,-1)

for i in range(N):
    new=[]
    for v in edge[i]:
        if v!=parent[i]:
            new.append(v)
    edge[i]=new


from collections import deque
ans = list(v for v in range(N) if deg[v]==0)
deq = deque(ans)
used = [0]*N

while deq:
    v = deq.popleft()
    for t in edge[v]:
        deg[t] -= 1
        if deg[t]==0:
            deq.append(t)
            ans.append(t)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

for v in ans[::-1]:
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        merged=[0]*(sz[v]+sz[nv]+1)
        for i in range(sz[v]+1):
            for j in range(sz[nv]+1):
                merged[i+j] +=dp[v][i]*dp[nv][j]
                merged[i+j]%=mod
        sz[v]+=sz[nv]
        dp[v] =merged
    dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod

print((-dp[0][0])%mod)

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 2*10**5
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

def func(n):
    if n%2==0:
        return (-g1[n]*g2[n//2]*pow(inverse[2],n//2,mod))%mod
    else:
        return 0

import sys

sys.setrecursionlimit(10**5)

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

parent=[0]*N
def prv(v,pv):
    for nv in edge[v]:
        if nv!=pv:
            parent[nv]=v
            prv(nv,v)

prv(0,-1)

for i in range(N):
    new=[]
    for v in edge[i]:
        if v!=parent[i]:
            new.append(v)
    edge[i]=new


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

def dfs(v,pv):
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        dfs(nv,v)
        merged=[0]*(sz[v]+sz[nv]+1)
        for i in range(sz[v]+1):
            for j in range(sz[nv]+1):
                merged[i+j] +=dp[v][i]*dp[nv][j]
                merged[i+j]%=mod
        sz[v]+=sz[nv]
        dp[v] =merged
    dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod


dfs(0,-1)

print((-dp[0][0])%mod)

Submission status: Time Limit Exceeded

Solution code:
mod = 10**9+7 #出力の制限
N = 2*10**5
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

def func(n):
    if n%2==0:
        return (-g1[n]*g2[n//2]*pow(inverse[2],n//2,mod))%mod
    else:
        return 0

import sys

sys.setrecursionlimit(10**5)

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

def dfs(v,pv):
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        if nv!=pv:
            dfs(nv,v)
            merged=[0]*(sz[v]+sz[nv]+1)
            for i in range(sz[v]+1):
                for j in range(sz[nv]+1):
                    merged[i+j] +=dp[v][i]*dp[nv][j]
                    merged[i+j]%=mod
            sz[v]+=sz[nv]
            dp[v] =merged
    dp[v][0]=(sum(func(k)*dp[v][k] for k in range(1,sz[v]+1)))%mod
    if v==0:
        dp[v][0]=(dp[v][0]-func(N)*dp[v][N])%mod

dfs(0,-1)

print((-func(N)-dp[0][0])%mod)

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
import numpy as np

MOD = 10 ** 9 + 7
N = int(input())

graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

"""
包除の原理。各頂点を根として
・偶数個を選ぶ、そこが反例となっている、他は何でもよい、
・奇数個を選ぶ、そこが反例となっている、他は何でもよい
・根を含む成分は保留してある。保留している頂点の数を持っておく。
・偶数個の場合と奇数の場合の差分だけ持っておく
"""

def dp_merge(data1,data2):
    N1 = len(data1) - 1
    N2 = len(data2) - 1
    data = np.zeros(N1+N2, dtype = np.int64)
    for n in range(1,N1+1):
        data[n:n+N2] += data1[n] * data2[1:] % MOD
    data %= MOD
    return data

fact_2 = [1,0,1]
for n in range(3,N+10):
    fact_2.append(fact_2[n-2] * (n-1) % MOD)
fact_2 = np.array(fact_2, dtype = np.int64)

def dp_add_edge(data):
    N = len(data) - 1
    data1 = np.zeros(N+2, dtype=np.int64)
    # 辺を反例に加えない
    data1[1:] = data
    # 辺を反例に加える
    data1[1] = - (data * fact_2[:N+1] % MOD).sum() % MOD
    return data1

def dfs(v, parent = None):
    data = None
    for y in graph[v]:
        if y == parent:
            continue
        data1 = dfs(y, v)
        # mergeする前に、最後の辺をひとつ加える
        data1 = dp_add_edge(data1)
        if data is None:
            data = data1
        else:
            data = dp_merge(data, data1)
    if data is None:
        return np.array([0,1],dtype=np.int64)
    return data

data = dfs(1)

answer = (data * fact_2[:N+1] % MOD).sum() % MOD

print(answer)

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
import numpy as np

MOD = 10 ** 9 + 7
N = int(input())

graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

"""
包除の原理。各頂点を根として
・偶数個を選ぶ、そこが反例となっている、他は何でもよい、
・奇数個を選ぶ、そこが反例となっている、他は何でもよい
・根を含む成分は保留してある。保留している頂点の数を持っておく。
・偶数個の場合と奇数の場合の差分だけ持っておく
"""

def dp_merge(data1,data2):
    N1 = len(data1) - 1
    N2 = len(data2) - 1
    data = np.zeros(N1+N2, dtype = np.int64)
    for n in range(1,N1+1):
        data[n:n+N2] += data1[n] * data2[1:] % MOD
    data %= MOD
    return data

fact_2 = [1,0,1]
for n in range(3,N+10):
    fact_2.append(fact_2[n-2] * (n-1) % MOD)
fact_2 = np.array(fact_2, dtype = np.int64)

def dp_add_edge(data):
    N = len(data) - 1
    data1 = np.zeros(N+2, dtype=np.int64)
    # 辺を反例に加えない
    data1[1:] = data
    # 辺を反例に加える
    data1[1] = - (data * fact_2[:N+1] % MOD).sum() % MOD
    return data1

def dfs(v, parent = None):
    data = None
    for y in graph[v]:
        if y == parent:
            continue
        data1 = dfs(y, v)
        # mergeする前に、最後の辺をひとつ加える
        data1 = dp_add_edge(data1)
        if data is None:
            data = data1
        else:
            data = dp_merge(data, data1)
    if data is None:
        return np.array([0,1],dtype=np.int64)
    return data

data = dfs(1)

answer = (data * fact_2[:N+1] % MOD).sum() % MOD

print(answer)

arr = np.arange(5)
arr

np.roll(arr,2)

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
import numpy as np

MOD = 10 ** 9 + 7
N = int(input())

graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

"""
包除の原理。各頂点を根として
・偶数個を選ぶ、そこが反例となっている、他は何でもよい、
・奇数個を選ぶ、そこが反例となっている、他は何でもよい
・根を含む成分は保留してある。保留している頂点の数を持っておく。
・偶数個の場合と奇数の場合の差分だけ持っておく
"""

def dp_merge(data1,data2):
    # parity, size
    N1 = len(data1) - 1
    N2 = len(data2) - 1
    data = np.zeros(N1+N2, dtype = np.int64)
    for n in range(N1+1):
        data[n:n+N2] += data1[n] * data2[1:] % MOD
    data %= MOD
    return data

fact_2 = [1,0,1]
for n in range(3,N+10):
    fact_2.append(fact_2[n-2] * (n-1) % MOD)
fact_2 = np.array(fact_2, dtype = np.int64)

def dp_add_edge(data):
    N = len(data) - 1
    data1 = np.zeros(N+2, dtype=np.int64)
    # 辺を反例に加えない
    data1[1:] = data
    # 辺を反例に加える
    data1[1] = - (data * fact_2[:N+1] % MOD).sum() % MOD
    return data1

def dfs(v, parent = None):
    data = None
    for y in graph[v]:
        if y == parent:
            continue
        data1 = dfs(y, v)
        # mergeする前に、最後の辺をひとつ加える
        data1 = dp_add_edge(data1)
        if data is None:
            data = data1
        else:
            data = dp_merge(data, data1)
    if data is None:
        return np.array([0,1],dtype=np.int64)
    return data

data = dfs(1)

answer = (data * fact_2[:N+1] % MOD).sum() % MOD

print(answer)

Submission status: Time Limit Exceeded

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
import numpy as np

MOD = 10 ** 9 + 7
N = int(input())

graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

"""
包除の原理。各頂点を根として
・偶数個を選ぶ、そこが反例となっている、他は何でもよい、
・奇数個を選ぶ、そこが反例となっている、他は何でもよい
・根を含む成分は保留してある。保留している頂点の数を持っておく。
"""

def dp_merge(data1,data2):
    # parity, size
    N1 = data1.shape[1] - 1
    N2 = data2.shape[1] - 1
    data = np.zeros((2,N1+N2), dtype = np.int64)
    for n in range(N1+1):
        data[0,n:n+N2] += data1[0,n] * data2[0,1:] % MOD
        data[0,n:n+N2] += data1[1,n] * data2[1,1:] % MOD
        data[1,n:n+N2] += data1[0,n] * data2[1,1:] % MOD
        data[1,n:n+N2] += data1[1,n] * data2[0,1:] % MOD
    data %= MOD
    return data

fact_2 = [1,0,1]
for n in range(3,N+10):
    fact_2.append(fact_2[n-2] * (n-1) % MOD)
fact_2 = np.array(fact_2, dtype = np.int64)

def dp_add_edge(data):
    # parity, size
    N = data.shape[1] - 1
    data1 = np.zeros((2,N+2), dtype=np.int64)
    # 辺を反例に加えない
    data1[:,1:] = data
    # 辺を反例に加える
    data1[0,1] = (data[1] * fact_2[:N+1] % MOD).sum() % MOD
    data1[1,1] = (data[0] * fact_2[:N+1] % MOD).sum() % MOD
    return data1

def dfs(v, parent = None):
    data = None
    for y in graph[v]:
        if y == parent:
            continue
        data1 = dfs(y, v)
        # mergeする前に、最後の辺をひとつ加える
        data1 = dp_add_edge(data1)
        if data is None:
            data = data1
        else:
            data = dp_merge(data, data1)
    if data is None:
        return np.array([[0,1],[0,0]],dtype=np.int64)
    return data

data = dfs(1)

answer = ((data[0] * fact_2[:N+1] % MOD).sum() - (data[1] * fact_2[:N+1] % MOD).sum()) % MOD

print(answer)

Submission status: Time Limit Exceeded

Solution code:
import sys

sys.setrecursionlimit(5001)
MOD = 10 ** 9 + 7

n = int(input())
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = map(int, line.split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)

double_factorial_odd = [0] * (n // 2)
prev = 1
for i in range(n // 2):
    prev = double_factorial_odd[i] = (2 * i + 1) * prev % MOD


def dfs(v, p):
    ret = [0, 1]
    for u in links[v]:
        if u == p:
            continue
        res = dfs(u, v)
        lt, ls = len(ret), len(res)
        mrg = [0] * (lt + ls - 1)
        for i in range(1 - lt % 2, lt, 2):
            c = ret[i]
            for j in range(1 - ls % 2, ls, 2):
                mrg[i + j] = (mrg[i + j] + c * res[j]) % MOD
        ret = mrg

    if len(ret) % 2 == 1:
        ret[0] = -sum(pattern * df % MOD for pattern, df in zip(ret[2::2], double_factorial_odd)) % MOD

    return ret


print(MOD - dfs(0, -1)[0])

Submission status: Time Limit Exceeded

Solution code:
import sys
from array import array
from itertools import islice

sys.setrecursionlimit(5001)
MOD = 10 ** 9 + 7

n = int(input())
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = map(int, line.split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)

double_factorial_odd = array('q', [0] * (n // 2))
prev = 1
for i in range(n // 2):
    prev = double_factorial_odd[i] = (2 * i + 1) * prev % MOD


def dfs(v, p):
    ret = array('q', [0, 1])
    for u in links[v]:
        if u == p:
            continue
        res = dfs(u, v)
        lt, ls = len(ret), len(res)
        mrg = array('q', [0] * (lt + ls - 1))
        for i, c in islice(enumerate(ret), 1 - lt % 2, None, 2):
            for j, d in islice(enumerate(res), 1 - ls % 2, None, 2):
                mrg[i + j] = (mrg[i + j] + c * d) % MOD
        ret = mrg

    if len(ret) % 2 == 1:
        ret[0] = -sum(pattern * df % MOD for pattern, df in zip(ret[2::2], double_factorial_odd)) % MOD

    return ret


print(MOD - dfs(0, -1)[0])

Submission status: Time Limit Exceeded

Solution code:
import sys
from itertools import islice

sys.setrecursionlimit(5001)
MOD = 10 ** 9 + 7

n = int(input())
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = map(int, line.split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)

double_factorial_odd = [0] * (n // 2)
prev = 1
for i in range(n // 2):
    prev = double_factorial_odd[i] = (2 * i + 1) * prev % MOD


def dfs(v, p):
    ret = [0, 1]
    for u in links[v]:
        if u == p:
            continue
        res = dfs(u, v)
        lt, ls = len(ret), len(res)
        mrg = [0] * (lt + ls - 1)
        for i, c in islice(enumerate(ret), 1 - lt % 2, None, 2):
            for j, d in islice(enumerate(res), 1 - ls % 2, None, 2):
                mrg[i + j] = (mrg[i + j] + c * d) % MOD
        ret = mrg

    if len(ret) % 2 == 1:
        ret[0] = -sum(pattern * df % MOD for pattern, df in zip(ret[2::2], double_factorial_odd)) % MOD

    return ret


print(MOD - dfs(0, -1)[0])

Submission status: Accepted

Solution code:
mod = 10**9+7 #出力の制限
N = 2*10**5
g1 = [1, 1] # 元テーブル
g2 = [1, 1] #逆元テーブル
inverse = [0, 1] #逆元テーブル計算用テーブル

for i in range( 2, N + 1 ):
    g1.append( ( g1[-1] * i ) % mod )
    inverse.append( ( -inverse[mod % i] * (mod//i) ) % mod )
    g2.append( (g2[-1] * inverse[-1]) % mod )

import sys

sys.setrecursionlimit(10**4)

N=int(input())
edge=[[] for i in range(N)]
parent=[0]*N
deg=[1]*N
deg[0]=0
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)


def prv(v,pv):
    for nv in edge[v]:
        if nv!=pv:
            parent[nv]=v
            prv(nv,v)

prv(0,-1)

for i in range(N):
    new=[]
    for v in edge[i]:
        if v!=parent[i]:
            new.append(v)
    edge[i]=new


from collections import deque
ans = list(v for v in range(N) if deg[v]==0)
deq = deque(ans)
used = [0]*N

while deq:
    v = deq.popleft()
    for t in edge[v]:
        deg[t] -= 1
        if deg[t]==0:
            deq.append(t)
            ans.append(t)


dp=[[] for i in range(N)]
sz=[0 for i in range(N)]

for v in ans[::-1]:
    sz[v]=1
    dp[v]=[0]*(sz[v]+1)
    dp[v][1]=1
    for nv in edge[v]:
        merged=[0]*(sz[v]+sz[nv]+1)
        for i in range(sz[v]+1):
            for j in range(sz[nv]+1):
                merged[i+j]=(merged[i+j]+dp[v][i]*dp[nv][j])%mod
        sz[v]+=sz[nv]
        dp[v] =merged
    for k in range(1,sz[v]+1):
        dp[v][0]=(dp[v][0]-(g1[k]*g2[k//2])%mod*((k+1)%2)*dp[v][k])%mod

print((-dp[0][0]*pow(inverse[2],N//2,mod))%mod)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)
import numpy as np

MOD = 10 ** 9 + 7
N = int(input())

graph = [[] for _ in range(N+1)]
for _ in range(N-1):
    x,y = map(int,input().split())
    graph[x].append(y)
    graph[y].append(x)

"""
包除の原理。各頂点を根として
・偶数個を選ぶ、そこが反例となっている、他は何でもよい、
・奇数個を選ぶ、そこが反例となっている、他は何でもよい
・根を含む成分は保留してある。保留している頂点の数を持っておく。
・偶数個の場合と奇数の場合の差分だけ持っておく
"""

def dp_merge(data1,data2):
    N1 = len(data1) - 1
    N2 = len(data2) - 1
    if N1 > N2:
        N1,N2 = N2,N1
        data1,data2 = data2,data1
    data = np.zeros(N1+N2, dtype = np.int64)
    for n in range(1,N1+1):
        data[n:n+N2] += data1[n] * data2[1:] % MOD
    data %= MOD
    return data

fact_2 = [1,0,1]
for n in range(3,N+10):
    fact_2.append(fact_2[n-2] * (n-1) % MOD)
fact_2 = np.array(fact_2, dtype = np.int64)

def dp_add_edge(data):
    N = len(data) - 1
    data1 = np.zeros(N+2, dtype=np.int64)
    # 辺を反例に加えない
    data1[1:] = data
    # 辺を反例に加える
    data1[1] = - (data * fact_2[:N+1] % MOD).sum() % MOD
    return data1

def dfs(v, parent = None):
    data = None
    for y in graph[v]:
        if y == parent:
            continue
        data1 = dfs(y, v)
        # mergeする前に、最後の辺をひとつ加える
        data1 = dp_add_edge(data1)
        if data is None:
            data = data1
        else:
            data = dp_merge(data, data1)
    if data is None:
        return np.array([0,1],dtype=np.int64)
    return data

data = dfs(1)

answer = (data * fact_2[:N+1] % MOD).sum() % MOD

print(answer)