bzoj4013: [HNOI2015]实验比较
这个题意花里胡哨的zzzzz
其实它是个树啊。。。然后看一下范围很显然是一个树背包啦
设f[i][j]表示以i为根的子树分成j段
对于当前两个子树合并,可以合出max(j1,j2)~j1+j2范围的段数
难点就在于怎么计算方案了(是真的没有想到啊T_T)
方程是这样的:singema f[x][i]*f[y][j]*C(k,i)*C(i,j-(k-i))
后面组合数的意思是:现在我有k个位置,我先把第一棵子树的i段放在不同的k个位置,就是C(k,i),再用第二棵子树的j段把i填剩下的k-i个位置填了,那么j还有j-(k-i)个没有填,要和第一棵子树的段合并,就是i个里面选j-(k-i)个
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=1e9+7; LL C[110][110]; void initC(int n) { C[0][0]=1; for(int i=1;i<=n;i++) { C[i][0]=1; for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } struct node { int x,y,next; }a[2100];int len,last[1100]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int fa[1100]; int dfs(int x) { int d=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(fa[y]==-1) { fa[y]=x; int s=dfs(y); if(s==-1)return s; d+=s; } else if(fa[y]!=x)return -1; } return d; } bool v[1100]; int n,tot[1100]; LL f[110][110],g[110]; void treeDP(int x) { tot[x]=1; bool bk=false; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false) { v[y]=true;treeDP(y); if(bk==false) { bk=true; tot[x]+=tot[y]; for(int i=1;i<=tot[x];i++)f[x][i]=f[y][i]; } else { for(int i=1;i<=tot[x];i++) for(int j=1;j<=tot[y];j++) for(int k=max(i,j);k<=i+j;k++) g[k]=(g[k]+f[x][i]*f[y][j]%mod*C[k][i]%mod*C[i][j-(k-i)]%mod)%mod; tot[x]+=tot[y]; for(int i=1;i<=tot[x];i++)f[x][i]=g[i],g[i]=0; } } } if(bk==false)f[x][1]=1; else { for(int i=tot[x];i>=1;i--)f[x][i]=f[x][i-1]; } } int findfa(int x) { if(x==fa[x])return x; fa[x]=findfa(fa[x]);return fa[x]; } struct edge{int x,y;}e[2100];int elen; char ss[5]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int m,x,y; scanf("%d%d",&n,&m);initC(n); for(int i=1;i<=n+1;i++)fa[i]=i; elen=0; for(int i=1;i<=m;i++) { scanf("%d%s%d",&x,ss+1,&y); if(ss[1]=='=')fa[findfa(x)]=findfa(y); else e[++elen].x=x,e[elen].y=y; } len=0; memset(last,0,sizeof(last)); memset(v,false,sizeof(v)); for(int i=1;i<=elen;i++) if(findfa(e[i].x)!=findfa(e[i].y)) ins(findfa(e[i].x),findfa(e[i].y)),v[findfa(e[i].y)]=true; for(int i=1;i<=n;i++) if(findfa(i)==i&&v[i]==false)ins(n+1,i); int cnt=0; for(int i=1;i<=n+1;i++) if(findfa(i)==i)cnt++; memset(fa,-1,sizeof(fa)); if(dfs(n+1)!=cnt)printf("0\n"); else { memset(v,false,sizeof(v)); treeDP(n+1); LL ans=0; for(int i=1;i<=n+1;i++)ans=(ans+f[n+1][i])%mod; printf("%d\n",ans); } return 0; }
pain and happy in the cruel world.