【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)}}$

做个树形背包即可。


 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 1010
#define llg long long
#define md 1000000007
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg n,m,fa[maxn],dad[maxn],bj[maxn],cnt,size[maxn],C[maxn][maxn],pos[maxn];
vector<llg>a[maxn];
llg f[maxn][maxn],g[maxn]; llg find(llg x) {if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x];} void init()
{
cin>>n>>m;
for (llg i=;i<=n;i++) fa[i]=i,C[i][]=;
C[][]=;
for (llg i=;i<=n;i++) for (llg j=;j<=i;j++) C[i][j]=(C[i-][j]+C[i-][j-])%md;
llg x,y; char s[];
for (llg i=;i<=m;i++)
{
scanf("%lld%s%lld",&x,s,&y);
if (s[]=='=')
{
llg f1=find(x),f2=find(y);
if (f1!=f2) fa[f2]=f1;
}
if (s[]=='<') dad[y]=x;
}
for (llg i=;i<=n;i++)
{
x=find(i);
y=find(dad[x]);
if (bj[x] || x==y) continue;
bj[x]=;
a[pos[y]].push_back(++cnt);
pos[x]=cnt;
}
memset(bj,,sizeof(bj));
} bool DP(llg x)
{
llg w=a[x].size(),v;
bj[x]=; bool flag=;
for (llg i=;i<w;i++)
{
v=a[x][i];
if (bj[v]) return ;
if (!DP(v)) return ;
if (flag)
{
flag=; size[x]=size[v];
for (llg i=;i<=size[v];i++) f[x][i]=f[v][i];
}
else
{
memset(g,,sizeof(g));
for (llg i=;i<=size[x];i++)
if (f[x][i])
for (llg j=;j<=size[v];j++)
if (f[v][j])
for (llg k=max(i,j);k<=i+j;k++)
g[k]+=((f[x][i]*f[v][j]) % md)*((C[k][i]*C[i][j-(k-i)]) %md),g[k]%=md;
size[x]+=size[v];
for (llg i=;i<=size[x];i++) f[x][i]=g[i];
}
}
if (x)
{
size[x]++;
if (flag) f[x][]=;
else for (llg i=size[x];i>=;i--) f[x][i]=f[x][i-];
}
return ;
} int main()
{
yyj("tree");
init();
if (!DP() || ((n==) && (m==))) {cout<<; return ;}
llg ans=;
for (llg i=;i<=size[];i++) ans+=f[][i],ans%=md;
cout<<ans;
return ;
}
上一篇:Swift自增和自增运算


下一篇:WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现