BZOJ4013: [HNOI2015]实验比较
2016-10-25 09:46
253 查看
先并查集合并‘=’,因为所有的Xi互不相同,所以合并完后应该是一个森林,如果出现环就无解。
我们新建一个根连向所有入度为0的点,就变成了一棵树,考虑树形DP。
因为只要两点不是其中一点是另一点的祖先的关系,他们就可以划‘=’因为大小关系不确定,所以将‘=’连接的看做一块,f[i][j]表示以i为根的子树分成了j块
转移的话,不合并块就是排列组合问题,如果合并块的话,假设不同子树的i个块和j个块合并,合并成k块,因为可以推出一棵子树上的块不能合并(否则方案数会算重复),所以问题可以转化成i个1,j个0,放进k个格子,同一个格子不能放多个1或多个0,先将1全放进去,剩下的用0补满,多余的j−(k−i)个0在i个位置选j−(k−i)个位置,那么方案数就是Cik∗Cj−(k−i)i
a1,a2是x的两个孩子,合并后视作新的孩子a3,a3继续和其他孩子合并f[a3][i]=f[a1][j]∗f[a2][k]∗Cji∗Ck−(i−j)j最后合并到只剩一个孩子y,因为节点x不能和其子树上的点合并,所以f[x][i]=f[y][i−1]
code:
我们新建一个根连向所有入度为0的点,就变成了一棵树,考虑树形DP。
因为只要两点不是其中一点是另一点的祖先的关系,他们就可以划‘=’因为大小关系不确定,所以将‘=’连接的看做一块,f[i][j]表示以i为根的子树分成了j块
转移的话,不合并块就是排列组合问题,如果合并块的话,假设不同子树的i个块和j个块合并,合并成k块,因为可以推出一棵子树上的块不能合并(否则方案数会算重复),所以问题可以转化成i个1,j个0,放进k个格子,同一个格子不能放多个1或多个0,先将1全放进去,剩下的用0补满,多余的j−(k−i)个0在i个位置选j−(k−i)个位置,那么方案数就是Cik∗Cj−(k−i)i
a1,a2是x的两个孩子,合并后视作新的孩子a3,a3继续和其他孩子合并f[a3][i]=f[a1][j]∗f[a2][k]∗Cji∗Ck−(i−j)j最后合并到只剩一个孩子y,因为节点x不能和其子树上的点合并,所以f[x][i]=f[y][i−1]
code:
#include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<cmath> #include<ctime> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int maxn = 210; const ll Mod = 1e9+7; struct edge { int y,nex; edge(){} edge(int _y,int _nex){y=_y;nex=_nex;} }a[maxn<<1]; int root,len,fir[maxn]; void ins(int x,int y){a[++len]=edge(y,fir[x]);fir[x]=len;} int q[maxn][3],n,m; int _in[maxn],fa[maxn]; int find_f(int x){return fa[x]==x?x:fa[x]=find_f(fa[x]);} ll c[maxn][maxn],f[maxn][maxn],siz[maxn],sizg[maxn],g[maxn][maxn]; bool v[maxn],mp[maxn][maxn]; void dfs(int x) { siz[x]=1; sizg[x]=0; for(int k=fir[x];k;k=a[k].nex) { int y=a[k].y; dfs(y); siz[x]+=siz[y]; if(!sizg[x]) { sizg[x]=siz[y]; for(int j=1;j<=sizg[x];j++) g[x][j]=f[y][j]; } else { for(int j=1;j<=sizg[x];j++) if(g[x][j]) for(int l=1;l<=siz[y];l++) if(f[y][l]) { int dn=max(j,l); for(int k=dn;k<=j+l;k++) (f[x][k]+=g[x][j]*f[y][l]%Mod*c[k][j]%Mod*c[j][l-(k-j)]%Mod)%=Mod; } sizg[x]+=siz[y]; for(int i=1;i<=sizg[x];i++) { g[x][i]=f[x][i];f[x][i]=0; } } } if(!sizg[x]) f[x][1]=1; else for(int i=2;i<=siz[x];i++) f[x][i]=g[x][i-1]; } bool judge(int x) { if(v[x])return false; v[x]=true; for(int k=fir[x];k;k=a[k].nex) if(!judge(a[k].y))return false; return true; } int main() { char st[110]; scanf("%d%d",&n,&m); c[0][0]=1; for(int i=1;i<=n;i++) { c[i][0]=1; fa[i]=i; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%Mod; } for(int i=1;i<=m;i++) { scanf("%d",&q[i][1]); scanf("%s",st); scanf("%d",&q[i][2]); if(st[0]=='<') q[i][0]=1; else { q[i][0]=0; fa[find_f(q[i][1])]=find_f(q[i][2]); } } memset(_in,0,sizeof _in); for(int i=1;i<=m;i++) { if(q[i][0]==1) { int f1=find_f(q[i][1]),f2=find_f(q[i][2]); if(!mp[f1][f2]) { _in[f2]++; ins(f1,f2); mp[f1][f2]=true; } } } for(int i=1;i<=n;i++) { memset(v,false,sizeof v); if(!judge(i)){printf("0\n");return 0;} } root=n+1; for(int i=1;i<=n;i++) if(_in[find_f(i)]==0&&!mp[root][fa[i]]) {ins(root,fa[i]);mp[root][fa[i]]=true;} dfs(root); ll ret=0; for(int i=1;i<=siz[root];i++) (ret+=f[root][i])%=Mod; printf("%lld\n",ret); return 0; }
相关文章推荐
- bzoj4013[HNOI2015]实验比较
- bzoj4013: [HNOI2015]实验比较
- bzoj4013: [HNOI2015]实验比较
- bzoj4013: [HNOI2015]实验比较
- BZOJ4013: [HNOI2015]实验比较
- 【BZOJ 4013】[HNOI2015]实验比较
- [BZOJ4013][HNOI2015]实验比较(树形DP)
- bzoj 4013: [HNOI2015]实验比较 树形dp+排列组合
- 【题解】HNOI-2015实验比较
- [树形DP] BZOJ 4013 [HNOI2015]实验比较
- BZOJ 4013: [HNOI2015]实验比较
- 【LOJ】#2117. 「HNOI2015」实验比较
- [BZOJ4013][HNOI2015]实验比较-树形DP
- 【BZOJ】4013: [HNOI2015]实验比较
- [HNOI 2015]实验比较
- 【bzoj4013】 HNOI2015—实验比较
- HNOI2015 实验比较
- BZOJ 4013 【HNOI2015】 实验比较
- BZOJ4013 : [HNOI2015]实验比较
- bzoj 4013: [HNOI2015]实验比较 (树形DP+组合数学)