zoukankan      html  css  js  c++  java
  • 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
    ",sum[1][size[1]]);
    75     }
    76     return 0;
    77 }
    bzoj3167
  • 相关阅读:
    浅谈Lyndon分解
    【CF914G】Sum the Fibonacci(FWT)
    【洛谷6914】[ICPC2015 WF] Tours(非树边随机边权,树边边权异或)
    【洛谷7143】[THUPC2021 初赛] 线段树(动态规划)
    【洛谷7325】[WC2021] 斐波那契(数论)
    【CF666E】Forensic Examination(广义后缀自动机+线段树合并)
    【CF685C】Optimal Point(二分答案)
    【洛谷7364】有标号二分图计数(多项式开根)
    【CF679E】Bear and Bad Powers of 42(ODT+线段树)
    【洛谷5307】[COCI2019] Mobitel(动态规划)
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7752921.html
Copyright © 2011-2022 走看看