P4099 [HEOI2013]SAO

Posted tyher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4099 [HEOI2013]SAO相关的知识,希望对你有一定的参考价值。

链接P4099 [HEOI2013]SAO

  • 如果真的把这个题当作图去做就炸了……还是考虑树怎么做。
  • 因为这个不是选父亲才能选子树,他是树型依赖背包的升级版,存在选子树才能选父亲的情况。
  • (f_{i,j})表示(i)节点的子树,(i)号节点在这个子树的拓扑位置为(j)的方案数。
  • 这样的好处在于我们可以很方便的计算下面的组合数。
  • 类似与树型背包的转移,儿子(to)转移到(i)相当于原来的拓扑序(S)和儿子的拓扑序(T)进行合并。
  • 先枚举 (u)(v) ,考虑如何从 (f′_{i,u})(f_{to,p})合并到 (f_{i,u+v})
  • 也就是枚举(i)在第一个拓扑序的位置,枚举儿子的拓扑序列哪一些必须在(i)之前,哪一些必须在(i)之后。
  • 如果是儿子比父亲先,所以在(i)之前的(k)才能转移。
  • 方程即:
    [f_{u,i+j}=f_{u,i}*C_{i+j-1}^{j}*C_{S_u+S_v-i-j}^{S_v-j}*sum f_{v,k}*[kleq j]]
  • 这是儿子在父亲之前的情况,前面两个组合数分别是(j)前面融入(i)前面和(j)后面融入(i)后面
  • 儿子在父亲后面同理。
    [f_{u,i+j}=f_{u,i}*C_{i+j-1}^{j}*C_{S_u+S_v-i-j}^{S_v-j}*sum f_{v,k}*[k>j]]
  • 朴素转移(O(n^3)),后面的(sum)显然可以前缀和优化为(O(n^2))
  • 注意一个实现细节,就是儿子在父亲后面的情况枚举(j)要从(0)开始,因为存在一个都不放在(i)前面的合法方案,儿子在父亲前面则不需要考虑。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int mod=1e9+7;
const int N=1001;
const int M=2001;
int t,n,cnt,u,v,sz[N],hd[N],to[M],w[M],nt[M],g[N][N],f[N][N];
int jic[M],inv[M],tmp[N];
char c;
int Qpow(R x,R y){
    R ans=1,bas=x;
    while(y){
        if(y&1)ans=1ll*ans*bas%mod;
        bas=1ll*bas*bas%mod,y>>=1;
    }return ans;
}
void link(R f,R t,R d){
    nt[++cnt]=hd[f],to[cnt]=t,w[cnt]=d,hd[f]=cnt;
}
int C(R x,R y){return 1ll*jic[y]*inv[x]%mod*inv[y-x]%mod;}
void add(R &x,R y){x=(x+y>=mod?x+y-mod:x+y);}
int gi(){
    R x=0,k=1;char c=getchar();
    while(c!=‘-‘&&(c<‘0‘||c>‘9‘))c=getchar();
    if(c==‘-‘)k=-1,c=getchar();
    while(c>=‘0‘&&c<=‘9‘)x=(x<<3)+(x<<1)+c-‘0‘,c=getchar(); 
    return x*k;
}
void Dfs(R i,R fm){
    sz[i]=1,f[i][1]=1;
    for(R k=hd[i];k;k=nt[k]){
        if(to[k]==fm)continue;
        Dfs(to[k],i);
        for(R j=sz[i]+sz[to[k]];j>=1;--j)tmp[j]=0;
        if(w[k]){
            for(R u=1;u<=sz[i];++u)
                for(R v=0;v<=sz[to[k]];++v){
                    R tik=1ll*f[i][u]*C(sz[to[k]]-v,sz[i]+sz[to[k]]-u-v)%mod;
                    tik=1ll*tik*C(v,u+v-1)%mod*(g[to[k]][sz[to[k]]]-g[to[k]][v]+mod)%mod;
                    add(tmp[u+v],tik);
                }
        }
        else{
            for(R u=1;u<=sz[i];++u)
                for(R v=1;v<=sz[to[k]];++v){
                    R tik=1ll*f[i][u]*C(sz[to[k]]-v,sz[i]+sz[to[k]]-u-v)%mod;
                    tik=1ll*tik*C(v,u+v-1)%mod*g[to[k]][v]%mod;
                    add(tmp[u+v],tik);
                }
        }
        sz[i]+=sz[to[k]];
        for(R j=sz[i];j>=1;--j)f[i][j]=tmp[j];
    }
    for(R j=1;j<=sz[i];++j)g[i][j]=(g[i][j-1]+f[i][j])%mod;
}
void sol(){
    memset(hd,0,sizeof(hd));
    memset(g,0,sizeof(g));
    memset(f,0,sizeof(f));
    n=gi(),cnt=0;
    for(R i=1;i<n;++i){
//      u=gi(),cin>>c,v=gi();
        u=gi()+1,cin>>c,v=gi()+1;
//      cout<<u<<‘ ‘<<v<<‘ ‘<<c<<endl;
        if(c==‘<‘)link(u,v,0),link(v,u,1);
        else link(u,v,1),link(v,u,0);
    }
    Dfs(1,0);R ans=0;
    for(R i=1;i<=n;++i)add(ans,f[1][i]);
    cout<<ans<<endl;
}
int main(){
    t=gi(),jic[0]=1,inv[0]=1;
    for(R i=1;i<N;++i)jic[i]=1ll*jic[i-1]*i%mod;
    inv[N-1]=Qpow(jic[N-1],mod-2);
    for(R i=N-2;i>=1;--i)inv[i]=1ll*inv[i+1]*(i+1)%mod;
    while(t--)sol();
    return 0;
}


以上是关于P4099 [HEOI2013]SAO的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ3167][P4099][HEOI2013]SAO(树形DP)

BZOJ 3167: [Heoi2013]Sao

[BZOJ3167][Heoi2013]Sao

[HEOI2013]SAO

BZOJ 3167: [Heoi2013]Sao

[HEOI 2013]SAO