题目大意
给定一个
n
个点的仙人球。
现在要从图中选出不超过
Data Constraint
题解
将仙人掌进行缩环之后,显然能得到一棵树。
然后就可以树形DP了。设
fi,j
表示第
i
个环的子树中,环
至于处理环,可以先将一条边断开,然后做一个后缀和前缀合并。
时间复杂度:
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
#define K 100 + 10
#define N 5000 + 10
#define M 20000000 + 10
typedef long long ll ;
const int MO = 1e9 + 7 ;
vector < int > G[N] ;
bool vis[N] ;
int DFN[N] , LOW[N] , S[N] , Tim ;
ll f[N][K] , f1[N][K] , f2[N][K] , g[N][K] , h[N][K] ;
int Cir[N][2*N] , Size[N] , Belong[N] , from[N] , st[N] ;
int Node[M] , Next[M] , Head[N] , tot = 1 ;
int n , m , lim , Cnt , ans ;
void link( int u , int v ) {
Node[++tot] = v ;
Next[tot] = Head[u] ;
Head[u] = tot ;
}
void Tarjan( int x , int fa ) {
S[++S[0]] = x ;
DFN[x] = LOW[x] = ++ Tim ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( p == (fa ^ 1) ) continue ;
if ( !DFN[Node[p]] ) {
Tarjan( Node[p] , p ) ;
LOW[x] = min( LOW[x] , LOW[Node[p]] ) ;
} else LOW[x] = min( LOW[x] , DFN[Node[p]] ) ;
}
if ( DFN[x] == LOW[x] ) {
++ Cnt ;
while ( S[0] ) {
Belong[S[S[0]]] = Cnt ;
Size[Cnt] ++ ;
Cir[Cnt][Size[Cnt]] = S[S[0]] ;
from[S[S[0]]] = Size[Cnt] ;
S[0] -- ;
if ( S[S[0]+1] == x ) break ;
}
}
}
void PreDFS( int x ) {
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( vis[Node[p]] ) continue ;
vis[Node[p]] = 1 ;
int u = Belong[x] , v = Belong[Node[p]] ;
if ( u != v ) {
G[u].push_back(v) ;
st[v] = Node[p] ;
}
PreDFS( Node[p] ) ;
}
}
void DFS( int x , int fa ) {
for (int i = 0 ; i < (signed)G[x].size() ; i ++ )
DFS( G[x][i] , x ) ;
for (int i = 1 ; i <= Size[x] ; i ++ ) {
int now = Cir[x][i] , flag = 0 ;
h[now][1] = 1 ;
for (int p = Head[now] ; p ; p = Next[p] ) {
if ( Belong[Node[p]] == Belong[now] || Belong[Node[p]] == fa ) continue ;
if ( flag == 0 ) {
flag = 1 ;
for (int j = 1 ; j < lim ; j ++ ) {
h[now][j+1] = f[Belong[Node[p]]][j] ;
}
} else {
for (int j = lim ; j >= 1 ; j -- ) {
if ( h[now][j] == 0 ) continue ;
for (int k = 1 ; k <= lim - j ; k ++ ) {
h[now][j+k] = (h[now][j+k] + f[Belong[Node[p]]][k] * h[now][j] % MO) % MO ;
}
}
}
}
}
int l = from[st[x]] ;
int r = l + Size[x] - 1 ;
for (int i = r ; i >= l ; i -- ) {
int now = Cir[x][i] ;
if ( i < r ) {
int last = Cir[x][i+1] ;
for (int j = 1 ; j <= lim ; j ++ ) {
if ( h[now][j] == 0 ) continue ;
for (int k = 1 ; j + k <= lim ; k ++ ) {
g[now][j+k] = (g[now][j+k] + h[now][j] * g[last][k] % MO) % MO ;
}
}
} else {
for (int j = 1 ; j <= lim ; j ++ ) g[now][j] = h[now][j] ;
}
}
//f[x][1] = 1 ;
for (int i = r - 1 ; i >= l ; i -- ) {
int now = Cir[x][i] ;
int last = Cir[x][i+1] ;
for (int j = 1 ; j <= lim ; j ++ ) g[now][j] = (g[now][j] + g[last][j]) % MO ;
}
for (int i = l ; i <= r ; i ++ ) {
int now = Cir[x][i] ;
if ( i == l ) {
for (int j = 1 ; j <= lim ; j ++ ) f1[now][j] = h[now][j] ;
} else {
int pre = Cir[x][i-1] ;
for (int j = 1 ; j <= lim ; j ++ ) {
if ( h[now][j] == 0 ) continue ;
for (int k = 1 ; j + k <= lim ; k ++ ) {
f1[now][j+k] = (f1[now][j+k] + h[now][j] * f1[pre][k] % MO) % MO ;
}
}
}
if ( Size[x] == 1 ) {
for (int j = 1 ; j <= lim ; j ++ ) f[x][j] = f1[now][j] ;
} else {
if ( i + 2 <= r ) {
int next = Cir[x][i+2] ;
for (int j = 1 ; j <= lim ; j ++ ) f[x][j] = (f[x][j] + f1[now][j]) % MO ;
for (int j = 1 ; j <= lim ; j ++ ) {
if ( f1[now][j] == 0 ) continue ;
for (int k = 1 ; j + k <= lim ; k ++ ) {
f[x][j+k] = (f[x][j+k] + f1[now][j] * g[next][k] % MO) % MO ;
}
}
} else {
for (int j = 1 ; j <= lim ; j ++ ) f[x][j] = (f[x][j] + f1[now][j]) % MO ;
}
}
}
for (int i = l + 1 ; i <= r ; i ++ ) {
int now = Cir[x][i] ;
f2[now][0] = 1 ;
if ( i == l + 1 ) {
for (int j = 1 ; j <= lim ; j ++ ) f2[now][j] = h[now][j] ;
} else {
int pre = Cir[x][i-1] ;
for (int j = 1 ; j <= lim ; j ++ ) {
if ( h[now][j] == 0 ) continue ;
for (int k = 0 ; j + k <= lim ; k ++ ) {
f2[now][j+k] = (f2[now][j+k] + h[now][j] * f2[pre][k] % MO) % MO ;
}
}
}
for (int j = 1 ; j <= lim ; j ++ ) {
ans = (ans + f2[now][j]) % MO ;
}
}
for (int i = 1 ; i <= lim ; i ++ ) ans = (ans + f[x][i]) % MO ;
}
int main() {
freopen( "cactus.in" , "r" , stdin ) ;
freopen( "cactus.out" , "w" , stdout ) ;
scanf( "%d%d%d" , &n , &m , &lim ) ;
for (int i = 1 ; i <= m ; i ++ ) {
int u , v ;
scanf( "%d%d" , &u , &v ) ;
link( u , v ) ;
link( v , u ) ;
}
for (int i = 1 ; i <= n ; i ++ ) {
if ( !DFN[i] ) Tarjan( i , 1 ) ;
}
for (int i = 1 ; i <= Cnt ; i ++ ) {
for (int j = 1 ; j <= Size[i] ; j ++ ) Cir[i][Size[i]+j] = Cir[i][j] ;
}
vis[1] = 1 ;
PreDFS( 1 ) ;
st[Belong[1]] = 1 ;
DFS( Belong[1] , 0 ) ;
printf( "%d\n" , ans ) ;
}
以上.