码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4013[HNOI2015]实验比较

时间:2015-11-23 23:11:47      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:

http://www.lydsy.com/JudgeOnline/problem.php?id=4013

这题真是极好的。

首先,用并查集合并相等的点,并用并查集的根作为代表的点。

然后dfs一次,看一下有没有环,如有环,那么无解,直接输出0。

我们发现图其实是一个由一些有根树组成的森林。为了方便计算,我们新建一个虚拟根,然后所有有根树的根都指向这个根,那么现在原图就变成一棵树了。

用树形DP。

记$f[i][j]$表示以$i$为根的子树,构成长度为$j$的序列的方案数。

那么怎么合并子树呢?

假设点$x$有两个儿子$u$和$v$。

假设子树$u$形成了长度为$j$的序列,子树$v$形成了长度为$k$的序列,两个序列合并后,形成的新的序列的长度为$p$。

我们考虑在子树$u$形成的长度为$j$的序列的基础上,加入$k$个点。

我们发现,有$p-j$个点是插入在$j+1$个缝隙中的(同一个缝隙可插多个),有$C_{j+1+p-j-1}^{p-j}$中方案;有$k-(p-j)$个点是与原序列的$i$个点合并的,有$C_{j}^{k-(p-j)}$种方案。

所以$f[x][p+1]+=C_{j+1+p-j-1}^{p-j}*C_{i}^{k-(p-j)}*f[u][j]*f[v][k]$

注意还要在前面加上$x$这个点,所以序列的长度是$p+1$。

如果有多个儿子,类似做法即可。

技术分享
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
 
using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b)  for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define p_b(a) push_back(a)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

inline int sgn(DB x){if(abs(x)<1e-9)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=- && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==-){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-0,z=getchar());
        return (neg)?-res:res; 
    }
LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=- && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==-){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-0,z=getchar());
        return (neg)?-res:res; 
    }

const int maxn=100;
const LL MOD=1000000007;

int n,m;

int pa[maxn+10];
int getrt(int a){return (pa[a]<0)?a:pa[a]=getrt(pa[a]);}
void uni(int a,int b)
  {
      int f1=getrt(a),f2=getrt(b);
      if(f1==f2)return;
      if(pa[f1]>pa[f2])swap(f1,f2);
      pa[f1]+=pa[f2];
      pa[f2]=f1;
  }

int fa[maxn+10];
int now,info[maxn+10];
struct Tedge{int v,next;}edge[maxn+10];
int sz[maxn+10];

void addedge(int u,int v){edge[++now]=(Tedge){v,info[u]};info[u]=now;}

int flag,vis[maxn+10];
void dfs(int u)
  {
      if(flag)return;
      vis[u]=1;sz[u]=1;
      int i,v;
      for(i=info[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)if(vis[v]){flag=1;return;}else{dfs(v);sz[u]+=sz[v];}
  }

LL C[2*maxn+20][2*maxn+20];
LL f[maxn+20][maxn+20],tmpf[maxn+20][maxn+20];
LL ans;

void dp(int u)
  {
      if(info[u]==-1){f[u][1]=1;return;}
      int i,v,j,k,p,all=0,ty=0;
      for(i=info[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)
        {
            dp(v);
            if(ty==0){re(j,1,sz[v])f[u][j]=f[v][j];all+=sz[v];ty=1;continue;}
            re(j,1,all+sz[v])tmpf[u][j]=0;
            re(j,1,all)if(f[u][j]!=0)re(k,1,sz[v])if(f[v][k]!=0)re(p,j,j+k)(tmpf[u][p]+=C[j+1+p-j-1][p-j]*C[j][k-(p-j)]%MOD*f[u][j]%MOD*f[v][k]%MOD)%=MOD;
            re(j,1,all+sz[v])f[u][j]=tmpf[u][j];
            all+=sz[v];
        }
      red(j,all+1,2)f[u][j]=f[u][j-1];f[u][1]=0;
  }

int x[maxn+10],y[maxn+10];char t[maxn+10];
int bak[maxn+10][maxn+10];

int main()
  {
      freopen("bzoj4013.in","r",stdin);
      freopen("bzoj4013.out","w",stdout);
      int i,j,k,l;
      n=gint();m=gint();
      mmst(pa,-1);
      re(i,1,m)
        {
            SF("%d %c %d\n",&x[i],&t[i],&y[i]);
            if(t[i]===)uni(x[i],y[i]);
        }
      now=-1;mmst(info,-1);
        re(i,1,m)if(t[i]==<)
          {
              int u=getrt(x[i]),v=getrt(y[i]);
              if(!bak[u][v])addedge(u,v),bak[u][v]=1,fa[v]=u;
          }
        re(i,1,n)if(i==getrt(i) && !fa[i])addedge(0,i);
        re(i,0,n)if(i==getrt(i) && !vis[i])
          {
              dfs(i);
              if(flag){PF("0\n");return 0;}
          }
        C[0][0]=1;
        re(i,1,2*n+10){C[i][0]=1;re(j,1,2*n+10)C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;}
        dp(0);
        re(i,1,sz[0])(ans+=f[0][i])%=MOD;
        cout<<ans<<endl;
        return 0;
    }
View Code

 

bzoj4013[HNOI2015]实验比较

标签:

原文地址:http://www.cnblogs.com/maijing/p/4989821.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!