luogu P3240 [HNOI2015]實驗比較
阿新 • • 發佈:2019-02-23
++i mat 通過 memcpy \n ans c++ 題目中的 getch
傳送門
首先根據題目條件,題目中如果是=的點可以縮起來,然後\(a<b\)連邊\(a\rightarrow b\),而且所有點入度為最多1,那麽判掉有環的不合法情況,題目中的依賴關系就是一顆外向樹森林,可以通過建一個另外的點向每棵樹的根連邊,能得到一顆外向樹
然後就是dp,這裏把打等號的一些相鄰的數看成一個數,設\(f_{i,j}\)表示i點子樹序列長度為j的方案,轉移將兒子依次合並,即\(f_{x,l}\leftarrow f_{x,j}*f_{y,k}*g_{j,k,l}\)
上面的g是一個長度為j一個長度為k的序列合並成長度為l的序列方案數,轉移枚舉最後一個數是第一個序列的,第二個序列的或者是合並起來的
#include<bits/stdc++.h> #define LL long long #define db double #define il inline #define re register using namespace std; const int N=100+10,mod=1e9+7; il int rd() { int x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int to[N<<1],nt[N<<1],hd[N],dg[N],tot=1; il void add(int x,int y) { ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot,++dg[y]; } int f[N][N],g[N][N][N<<1],d[N],sz[N]; void dp(int x) { sz[x]=f[x][0]=1; for(int h=hd[x];h;h=nt[h]) { int y=to[h]; dp(y); memset(d,0,sizeof(d)); for(int i=0;i<sz[x];++i) for(int j=1;j<=sz[y];++j) for(int k=1;k<=i+j;++k) d[k]=(d[k]+1ll*f[x][i]*f[y][j]%mod*g[i][j][k]%mod)%mod; sz[x]+=sz[y]; memcpy(f[x],d,sizeof(d)); } for(int i=sz[x];i;--i) f[x][i]=f[x][i-1]; f[x][0]=0; } int n,m,e[N][2],ff[N]; il int findf(int x){return ff[x]==x?x:ff[x]=findf(ff[x]);} bool v[N]; bool check(int x) { if(v[x]) return 0; v[x]=1; for(int h=hd[x];h;h=nt[h]) if(!check(to[h])) return 0; v[x]=0; return 1; } int main() { n=rd(),m=rd(); for(int i=1;i<=n;++i) ff[i]=i; for(int i=1;i<=m;++i) { int x=rd(),z=(getchar()=='<'),y=rd(); if(!z) --m,--i,ff[findf(x)]=findf(y); else e[i][0]=x,e[i][1]=y; } for(int i=1;i<=m;++i) add(findf(e[i][0]),findf(e[i][1])); for(int i=1;i<=n;++i) if(findf(i)==i&&!check(i)) return puts("0"),0; for(int i=1;i<=n;++i) if(!dg[i]&&findf(i)==i) add(n+1,i); g[0][0][0]=1; for(int i=0;i<=n;++i) for(int j=0;j<=n;++j) for(int k=1;k<=i+j;++k) { if(i) g[i][j][k]=(g[i][j][k]+g[i-1][j][k-1])%mod; if(j) g[i][j][k]=(g[i][j][k]+g[i][j-1][k-1])%mod; if(i&&j) g[i][j][k]=(g[i][j][k]+g[i-1][j-1][k-1])%mod; } dp(n+1); int ans=0,lim=1; for(int i=1;i<=n;++i) lim+=findf(i)==i; for(int i=1;i<=lim;++i) ans=(ans+f[n+1][i])%mod; printf("%d\n",ans); return 0; }
luogu P3240 [HNOI2015]實驗比較