[树形DP] BZOJ 4013 [HNOI2015]实验比较

来源:互联网 发布:苹果手机越狱软件 编辑:程序博客网 时间:2024/05/21 03:17

首先缩点 然后肯定会变成一颗森林 不然无解
弄一个超级根
然后 fu,k 表示子树 u 划分成 k 段的方案数
合并的时候 i 段和 j 段可以合并成 kk[max{i,j},i+j]
用组合数算一下就好了

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define cl(x) memset(x,0,sizeof(x))using namespace std;typedef long long ll;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}inline void read(char &x){  for (x=nc();!(x=='>' || x=='<' || x=='=');x=nc());}const int N=105;const int P=1e9+7;ll C[N][N];inline void Pre(int n){  C[0][0]=1;  for (int i=1;i<=n;i++){    C[i][0]=1;    for (int j=1;j<=n;j++)      C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;  }}struct edge{  int u,v,next;}G[N<<1];int head[N],inum;inline void add(int u,int v,int p){  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;}int vst[N],size[N];ll f[N][N],g[N];#define V G[p].vinline bool dfs(int u){  vst[u]=1; f[u][0]=1; size[u]=0;  for (int p=head[u];p;p=G[p].next){    if (vst[V]) return 0;    if (!dfs(V)) return 0;    cl(g);    for (int i=0;i<=size[u];i++)      if (f[u][i])    for (int j=0;j<=size[V];j++)      if (f[V][j])        for (int k=max(i,j);k<=i+j;k++)          g[k]+=f[u][i]*f[V][j]%P*C[k][i]%P*C[i][j-(k-i)]%P;    size[u]+=size[V];    for (int i=0;i<=size[u];i++) f[u][i]=g[i]%P;  }  if (u){    size[u]++;    for (int i=size[u];i;i--) f[u][i]=f[u][i-1];    f[u][0]=0;  }  return 1;}int fat[N];inline int Fat(int u){  return u==fat[u]?u:fat[u]=Fat(fat[u]);}int n,m;int _u[N],_v[N];int deg[N];int main(){  int iu,iv; char c;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  read(n); read(m); Pre(n);  for (int i=1;i<=n;i++) fat[i]=i;  int t=m; m=0;  while (t--){    read(iu); read(c); read(iv);    if (c=='=') { fat[Fat(iu)]=Fat(iv); continue; }    if (c=='>') swap(iu,iv);    _u[++m]=iu,_v[m]=iv;  }  for (int i=1;i<=m;i++){    iu=Fat(_u[i]),iv=Fat(_v[i]);    if (iu==iv) return printf("0\n"),0;    add(iu,iv,++inum); deg[iv]++;      }  for (int i=1;i<=n;i++)    if (Fat(i)==i && !deg[i])      add(0,i,++inum);  if (!dfs(0)) return printf("0\n"),0;  ll ans=0;  for (int i=1;i<=size[0];i++) ans+=f[0][i];  printf("%d\n",ans%P);  return 0;}
0 0
原创粉丝点击