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


    题目描述

    Welcome to SAO ( Strange and Abnormal Online)。这是一个 VR MMORPG, 含有 n 个关卡。但是,挑战不同关卡的顺序是一个很大的问题。

    有 n – 1 个对于挑战关卡的限制,诸如第 i 个关卡必须在第 j 个关卡前挑战, 或者完成了第 k 个关卡才能挑战第 l 个关卡。并且,如果不考虑限制的方向性, 那么在这 n – 1 个限制的情况下,任何两个关卡都存在某种程度的关联性。即, 我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集之间没有任 何限制。

    输入输出格式

    输入格式:

    第一行,一个整数 T,表示数据组数。

    对于每组数据,第一行一个整数 n,表示关卡数。接下来 n – 1 行,每行为 “i sign j”,其中 0 ≤ i, j ≤ n – 1 且 i ≠ j,sign 为“<”或者“>”,表示第 i 个关卡 必须在第 j 个关卡前/后完成。

    输出格式:

    对于每个数据,输出一行一个整数,为攻克关卡的顺序方案个数,mod 1,000,000,007 输出。

    输入输出样例

    输入样例#1: 复制
    2 
    5 
    0 < 2 
    1 < 2 
    2 < 3 
    2 < 4 
    4 
    0 < 1 
    0 < 2 
    0 < 3
    输出样例#1: 复制
    4 
    6

    说明

    对于 20%的数据有 n ≤ 10。

    对于 40%的数据有 n ≤ 100。

    对于另外 20%的数据有,保证数据中 sign 只会是<,并且 i < j。

    对于 100%的数据有 T ≤ 5,1 ≤ n ≤ 1000。

    洛谷上都有的题BZ怎么还权限啊。。

    这题在某种意义上和 [HNOI2015]实验比较 有相似之处,主要思路是通过树形DP和组合数求解。

    直接给出状转方程:$f[i][j]$表示以$i$为根的子树中,$i$排在第$j$位的方案数。乘上组合数即可。

    https://www.cnblogs.com/CQzhangyu/p/7605703.html、

    最后前缀和优化那一步可能不太一样。但都是$O(n^3)$的,不知道是怎么过的,应该是因为根本跑不满。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mem(a) memset(a,0,sizeof(a))
     5 #define rep(i,l,r) for (int i=l; i<=r; i++)
     6 using namespace std;
     7 
     8 const int N=2100,mod=1000000007;
     9 char c;
    10 int n,T,u,v,cnt,C[N][N],g[N],f[N][N],to[N],sum[N][N],sz[N],h[N],nxt[N],val[N];
    11 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    12 void init(){ cnt=0; mem(h); mem(f); mem(sum); mem(sz); }
    13 
    14 void dfs(int x,int fa){
    15     f[x][1]=sum[x][1]=sz[x]=1;
    16     for (int i=h[x],s; i; i=nxt[i]) if ((s=to[i])!=fa){
    17         dfs(s,x); mem(g);
    18         if (val[i]==0){
    19             rep(i,1,sz[x]) if (f[x][i]) rep(j,0,sz[s]) if (sum[s][j])
    20                 g[i+j]=(g[i+j]+1ll*f[x][i]*sum[s][j]%mod*C[i+j-1][i-1]%mod*C[sz[x]-i+sz[s]-j][sz[x]-i]%mod)%mod;
    21         }else{
    22             rep(i,1,sz[x]) if (f[x][i]) rep(j,0,sz[s])
    23                 g[i+j]=(g[i+j]+1ll*f[x][i]*(sum[s][sz[s]]-sum[s][j]+mod)%mod*C[i+j-1][i-1]%mod*C[sz[x]-i+sz[s]-j][sz[x]-i])%mod;
    24         }
    25         sz[x]+=sz[s];
    26         rep(i,1,sz[x]) f[x][i]=g[i],sum[x][i]=(sum[x][i-1]+g[i])%mod;
    27     }
    28 }
    29 
    30 int main(){
    31     freopen("bzoj3167.in","r",stdin);
    32     freopen("bzoj3167.out","w",stdout);
    33     rep(i,0,1010) C[i][0]=1;
    34     rep(i,1,1010) rep(j,1,1010) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    35     for (scanf("%d",&T); T--; ){
    36         init(); scanf("%d",&n);
    37         rep(i,2,n){
    38             scanf("%d %c%d",&u,&c,&v); u++; v++;
    39             if (c=='>') swap(u,v);
    40             add(u,v,1); add(v,u,0);
    41         }
    42         dfs(1,0); printf("%d
    ",sum[1][sz[1]]);
    43     }
    44     return 0;
    45 }
  • 相关阅读:
    如何在SQLite中创建自增字段?
    Windows XP平台下编译boost[1.47及以上]
    智能指针的向下转型
    采用Boost::filesystem操作文件
    CodeSmith访问数据库
    std::string的一些操作
    PDF加入内嵌字体
    悟空和唐僧的对话
    收获和教训的一天配置ds1401
    vxworks的一个changlog
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8708417.html
Copyright © 2020-2023  润新知