bzoj 3167 SAO
Posted Ren_Ivan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于bzoj 3167 SAO的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ3167/4824[Heoi2013]Sao/[Cqoi2017]老C的键盘