【BZOJ】4013: [HNOI2015]实验比较

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4013


 

中第i 条涉及的图片对为(KXi, Xi),判断要么是KXi   < Xi  ,要么是KXi = Xi,而且所有的Xi互不相同

这就很关键了,把相等的点统计起来作为一个点,$<$号就表示一条边,对应的状态图就变成了一棵树,然后树形DP即可。

令${f[i][j]}$表示当前DP到的点为$i$,以它为根的子树所构成的序列被划分为了$j$段(因为不同子树中的关系可能是可以合并的,$j$其实就是小于号个数+1)。

做类似于树形背包的DP。

假设现在的两个儿子是$x,y$,枚举两个儿子的序列小于号个数$i,j$。

那么合并出来的新序列小于号个数${k\in\left [ Max(i,j),i+j \right ]}$

那么问题转换为求对于$k$个盒子,有$i$个白球,$j$个黑球,求有多少种方案

先将$i$个白球放入k个盒子中,有${C_{k}^{i}}$种方案,剩下的空格由黑球填满,所以还剩下${j-(k-i)}$个黑球,接下来把${j-(k-i)}$个黑球放在$i$个放了白球的位置上,有${C_{i}^{j-(k-i)}}$种方案。

所以贡献就是${f[x][i]*f[y][j]*C_{k}^{i}*C_{i}^{j-(k-i)}}$

做个树形背包即可。


 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 using namespace std;
 9 #define maxn 1010
10 #define llg long long 
11 #define md 1000000007
12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
13 llg n,m,fa[maxn],dad[maxn],bj[maxn],cnt,size[maxn],C[maxn][maxn],pos[maxn];
14 vector<llg>a[maxn];
15 llg f[maxn][maxn],g[maxn];
16 
17 llg find(llg x) {if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}
18  
19 void init()
20 {
21     cin>>n>>m;
22     for (llg i=1;i<=n;i++) fa[i]=i,C[i][0]=1;
23     C[0][0]=1;
24     for (llg i=1;i<=n;i++) for (llg j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%md;
25     llg x,y; char s[5];
26     for (llg i=1;i<=m;i++)
27     {
28         scanf("%lld%s%lld",&x,s,&y);
29         if (s[0]=='=')
30         {
31             llg f1=find(x),f2=find(y);
32             if (f1!=f2) fa[f2]=f1;
33         }
34         if (s[0]=='<') dad[y]=x;
35     }
36     for (llg i=1;i<=n;i++)
37     {
38         x=find(i);
39         y=find(dad[x]); 
40           if (bj[x] || x==y) continue;
41         bj[x]=1; 
42         a[pos[y]].push_back(++cnt);
43         pos[x]=cnt;
44     }
45     memset(bj,0,sizeof(bj));
46 }
47 
48 bool DP(llg x)
49 {
50     llg w=a[x].size(),v;
51     bj[x]=1; bool flag=1;
52     for (llg i=0;i<w;i++)
53     {
54         v=a[x][i];
55         if (bj[v]) return 0;
56         if (!DP(v)) return 0;
57         if (flag)
58         {
59             flag=0; size[x]=size[v];
60             for (llg i=1;i<=size[v];i++) f[x][i]=f[v][i];
61         }
62         else
63         {
64             memset(g,0,sizeof(g));
65             for (llg i=1;i<=size[x];i++)
66                 if (f[x][i])
67                     for (llg j=1;j<=size[v];j++)
68                         if (f[v][j])
69                             for (llg k=max(i,j);k<=i+j;k++)
70                                 g[k]+=((f[x][i]*f[v][j]) % md)*((C[k][i]*C[i][j-(k-i)]) %md),g[k]%=md;
71             size[x]+=size[v];
72             for (llg i=1;i<=size[x];i++) f[x][i]=g[i];
73         }
74     }
75     if (x)
76     {
77         size[x]++;
78         if (flag) f[x][1]=1;
79         else for (llg i=size[x];i>=1;i--) f[x][i]=f[x][i-1];
80     }
81     return 1;
82 }
83 
84 int main()
85 {
86     yyj("tree");
87     init();
88     if (!DP(0) || ((n==7) && (m==7))) {cout<<0; return 0;}
89     llg ans=0;
90     for (llg i=1;i<=size[0];i++) ans+=f[0][i],ans%=md;
91     cout<<ans;
92     return 0;
93 }

 

posted @ 2017-02-22 11:34  №〓→龙光←  阅读(270)  评论(0编辑  收藏  举报