BZOJ 3167 [Heoi2013]Sao ——树形DP

唔,好题。

拓扑序的计数问题。

忽略边的方向,得到一棵树。

然后我们用$f[i][j]$表示节点$i$在子树中排第$j$位的方案数。

然后直接DP,可以得到$n^3$的算法,然后再用前缀和优化一下就是$n^2$可以过掉本题。

是BZOJ4824的强化版

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (ll i=j;i<=k;++i)
#define D(i,j,k) for (ll i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 1050
const ll md=1000000007;
 
ll h[maxn<<1],to[maxn<<1],ne[maxn<<1],en=0,n;
ll siz[maxn],tmp[maxn],w[maxn],lim[maxn];
ll dp[maxn][maxn],c[maxn][maxn],suf[maxn][maxn],pre[maxn][maxn];
char s[maxn];
void add(ll a,ll b,ll c)
{
    to[en]=b;ne[en]=h[a];w[en]=c;h[a]=en++;
}
 
ll C(ll n,ll m)
{
    if (n<0||m<0) return 0;
    return c[n][m];
}
 
void Tree_DP(ll o,ll fa)
{
    dp[o][1]=1;siz[o]=1;
    for (ll i=h[o];i>=0;i=ne[i])
    if (to[i]!=fa){
        Tree_DP(to[i],o);
        F(j,0,siz[o]+siz[to[i]]+2) tmp[j]=0;
        if (w[i]==1)
        {
            F(j,1,siz[o])
                if (dp[o][j]) F(_j,j,j+siz[to[i]]-1)
                    tmp[_j]+=(((dp[o][j]*suf[to[i]][_j-j+1])%md*C(_j-1,j-1))%md*C(siz[o]+siz[to[i]]-_j,siz[o]-j))%md,tmp[_j]%=md;
        }
        else
        {
            F(j,1,siz[o])
                if (dp[o][j]) F(_j,j+1,siz[to[i]]+j)
                    tmp[_j]+=(((dp[o][j]*((suf[to[i]][1]-suf[to[i]][_j-j+1])%md+md))%md*C(_j-1,j-1))%md*C(siz[o]+siz[to[i]]-_j,siz[o]-j))%md,tmp[_j]%=md;
        }
        siz[o]+=siz[to[i]];
        F(j,0,siz[o]) dp[o][j]=(tmp[j]%md+md)%md;
    }
    suf[o][siz[o]]=dp[o][siz[o]];
    D(i,siz[o],1) suf[o][i]=(suf[o][i+1]+dp[o][i])%md;
}
 
void Finout()
{
    freopen("in.txt","r",stdin);
    freopen("wa.txt","w",stdout);
//  freopen("keyboard.in","r",stdin); 
//  freopen("keyboard.out","w",stdout);
}
 
ll t; 
 
int main()
{
    scanf("%lld",&t);
    c[1][0]=1;c[1][1]=1;c[0][0]=1;
    F(i,2,maxn-1)
    {
        c[i][0]=1;
        F(j,1,maxn-1) c[i][j]=(c[i-1][j]+c[i-1][j-1])%md;
    }
    while (t--)
    {
        memset(dp,0,sizeof dp);
        memset(suf,0,sizeof suf);
        memset(h,-1,sizeof h);en=0;
        scanf("%lld",&n);
        F(i,2,n)
        {
            ll a,b,c;
            scanf("%lld",&a);
            a++;
            scanf("%s",s);
            scanf("%lld",&b);b++;
            switch(s[0])
            {
                case '<':c=1;break;
                case '>':c=-1;break;
            }
            add(a,b,c); add(b,a,-c);
        }
        Tree_DP(1,-1);
        ll ans=0;
        F(i,0,n) ans+=dp[1][i],ans%=md;
        printf("%lld\n",(ans%md+md)%md);
    }
}

  

posted @ 2017-04-13 22:34  SfailSth  阅读(132)  评论(0编辑  收藏  举报