1. 程式人生 > >luogu P3240 [HNOI2015]實驗比較

luogu P3240 [HNOI2015]實驗比較

++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]實驗比較