您的位置:首页 > 其它

[树形DP 杂题] SRM 562 div1 InducedSubgraphs

2017-04-05 21:07 483 查看
集训队作业传送门

给一棵n个结点的树,定义一个结点集合是连通的表示这棵树以这个集合为点集的导出子图是连通图。再给一个整数k,将树上的结点重新编号,使得对于任意一个满足1≤i≤n−k+1的i,都满足由所有编号在[i,i+k−1]内的结点组成的结点集合是连通的。问这样的编号方式有多少种。1≤k≤n≤41。

大概是分两种情况讨论 详见题解



中间一条链 两边两棵子树 父亲比儿子大或小 直接用组合数DP下



考虑把白点中最小点提到根 然后gi,j,k表示子树 i 中有 j 个蓝点 k 个红点

// BEGIN CUT HERE
#include<conio.h>
#include<sstream>
// END CUT HERE
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#include<set>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

const int N=55;
const int P=1e9+9;

ll C

,fac
;

inline void Pre(int n){
fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
C[0][0]=1;
for (int i=1;i<=n;i++){
C[i][0]=1;
for (int j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
}
}

struct edge{
int u,v,next;
}G[N<<1];
int head
,inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v

int n,m,K;
int fat
,depth
,size
;

inline void _dfs(int u,int fa){
depth[u]=depth[fa]+1; fat[u]=fa;
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
_dfs(V,u);
}

int vst
; ll f
;

inline void dfs(int u,int fa){
size[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa && !vst[V])
dfs(V,u),size[u]+=size[V];
int tot=size[u]-1; f[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa && !vst[V]){
f[u]=f[u]*f[V]%P*C[tot][size[V]]%P;
tot-=size[V];
}
}

inline int Solve1(){
ll ans=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
if (i==j) continue;
_dfs(i,0);
if (depth[j]==n-2*K+2){
for (int k=1;k<=n;k++) vst[k]=0;
for (int k=j;k!=i;k=fat[k]) vst[k]=1; vst[i]=1;
dfs(i,0); dfs(j,0);
if (size[i]==K && size[j]==K)
ans+=f[i]*f[j]%P;
}
}
return ans%P;
}

ll g

;

inline void dp(int u,int fa){
g[u][0][0]=1; size[u]=1;
for (int p=head[u];p;p=G[p].next)
if (V!=fa){
dp(V,u); size[u]+=size[V];
for (int i=m;~i;i--)
for (int j=m;~j;j--){
if (!g[u][i][j]) continue;
for (int a=0;a+i<=m;a++)
for (int b=0;b+j<=m;b++){
if (!a && !b) continue;
if (!g[V][a][b]) continue;
(g[u][i+a][j+b]+=g[u][i][j]*g[V][a][b]%P*C[i+a][i]%P*C[j+b][j]%P)%=P;
}
}
}
if (size[u]<=m){
dfs(u,fa);
(g[u][size[u]][0]+=f[u])%=P;
(g[u][0][size[u]]+=f[u])%=P;
}
}

inline int Solve2(){
ll ans=0;
m=n-K;
for (int i=1;i<=n;i++){
cl(g);
dp(i,0);
ans+=g[i][m][m];
}
return ans%P*fac[2*K-n-1]%P;
}

class InducedSubgraphs{
public:
int getCount(vector <int> edge1, vector <int> edge2, int k){
n=edge1.size()+1; K=k; cl(head); inum=0;
for (int i=0;i<(int)edge1.size();i++)
add(edge1[i]+1,edge2[i]+1,++inum),add(edge2[i]+1,edge1[i]+1,++inum);
Pre(n);
if (K==1 || K==n) return fac
;
if (2*K<=n)
return Solve1();
else
return Solve2();
}

// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); if ((Case == -1) || (Case == 6)) test_case_6(); }
private:
template <typename T> string print_array(const vector<T> &_V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = _V.begin(); iter != _V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { int Arr0[] = {0, 1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1, 2}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 2; int Arg3 = 2; verify_case(0, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_1() { int Arr0[] = {0, 1, 3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {2, 2, 2}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 3; int Arg3 = 12; verify_case(1, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_2() { int Arr0[] = {5, 0, 1, 2, 2}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1, 2, 4, 3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 3; int Arg3 = 4; verify_case(2, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_3() { int Arr0[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 11; int Arg3 = 481904640; verify_case(3, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_4() { int Arr0[] = {5, 9, 4, 10, 10, 0, 7, 6, 2, 1, 11, 8}
; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 0, 10, 3, 0, 6, 1, 1, 12, 12, 7, 11}
; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 6; int Arg3 = 800; verify_case(4, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_5() { int Arr0[] = {0, 5, 1, 0, 2, 3, 5}
; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {4, 7, 0, 6, 7, 5, 0}
; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 3; int Arg3 = 0; verify_case(5, Arg3, getCount(Arg0, Arg1, Arg2)); }
void test_case_6() { int Arr0[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 1; int Arg3 = 890964601; verify_case(6, Arg3, getCount(Arg0, Arg1, Arg2)); }

// END CUT HERE

};

// BEGIN CUT HERE
int main(){
InducedSubgraphs ___test;
___test.run_test(-1);
getch() ;
return 0;
}
// END CUT HERE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: