bzoj 3167 SAO

树dp

定义f[i][j]为i在其已合并子树内排名为j的方案数

O(n2)进行子树合并

转移时枚举他在已合并子树中的排名j和新合并子树中的排名k+1

当他比他儿子大的时候$f[x][j+k]=f[x][j]*{\sum{_{i}^{k}}}f[son][i]*C{_{j+k-1}^{j-1}}*C{_{size[x]+size[son]-j-k}^{size[x]-j}}$

后面两个组合数可以看作是有j+k-1个比他小的要选出j-1个放原子树中的,剩下的放新子树中的,后面就是比他大的,同理

当他比他儿子小的时候只需要把前缀和转化成后缀和即可。

代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define mod 1000000007
 7 #define LL long long
 8 #define N 1050
 9 using namespace std;
10 int e=1,head[N];
11 struct edge{
12     int v,w,next;
13 }ed[2*N];
14 void add(int u,int v,int w){
15     ed[e].v=v;ed[e].w=w;
16     ed[e].next=head[u];
17     head[u]=e++;
18 }
19 LL C[N][N],f[N][N],sum[N][N],g[N];
20 int fa[N],size[N];
21 void dfs(int x){
22     size[x]=1;f[x][1]=1;
23     for(int i=head[x];i;i=ed[i].next){
24         int v=ed[i].v;
25         if(v==fa[x])continue;
26         fa[v]=x;dfs(v);
27         for(int j=1;j<=size[x]+size[v];j++)g[j]=0;
28         for(int j=1;j<=size[x];j++){
29             for(int k=0;k<=size[v];k++){
30                 if(ed[i].w==1)
31                     (g[j+k]+=f[x][j]*sum[v][k]%mod*C[j+k-1][j-1]%mod*C[size[x]+size[v]-j-k][size[x]-j]%mod)%=mod;
32                 else
33                     (g[j+k]+=f[x][j]*(sum[v][size[v]]-sum[v][k]+mod)%mod*C[j+k-1][j-1]%mod*C[size[x]+size[v]-j-k][size[x]-j]%mod)%=mod;
34             }
35         }
36         size[x]+=size[v];
37         for(int j=1;j<=size[x];j++)f[x][j]=g[j];
38     }
39     for(int i=1;i<=size[x];i++)
40         sum[x][i]=(sum[x][i-1]+f[x][i])%mod;
41 }
42 void init(){
43     e=1;
44     memset(head,0,sizeof head);
45     memset(sum,0,sizeof sum);
46     memset(size,0,sizeof size);
47     memset(fa,0,sizeof fa);
48     memset(f,0,sizeof f);
49 }
50 int n;
51 char getc(){
52     char ch=getchar();
53     while((ch!='<')&&(ch!='>'))ch=getchar();
54     return ch;
55 }
56 signed main(){
57     int T;
58     scanf("%d",&T);
59     for(int i=0;i<=1000;i++){
60         C[i][0]=1;
61         for(int j=1;j<=i;j++)
62             C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
63     }
64     while(T--){
65         init();
66         scanf("%d",&n);
67         for(int i=1,u,v;i<n;i++){
68             scanf("%d",&u);char ch=getc();scanf("%d",&v);
69             u++;v++;
70             if(ch=='<'){add(u,v,0);add(v,u,1);}
71             if(ch=='>'){add(u,v,1);add(v,u,0);}
72         }
73         dfs(1);
74         printf("%lld\n",sum[1][size[1]]);
75     }
76     return 0;
77 }
bzoj3167

 

posted @ 2017-10-30 07:16  Ren_Ivan  阅读(345)  评论(0编辑  收藏  举报