BZOJ 4013: [HNOI2015]实验比较

9 篇文章 0 订阅
3 篇文章 0 订阅

挺不错的题啊 然而本蒟蒻一开始一脸懵逼

然后在dalao的指导下 再看了看 注意到有“对每张图片 i,小 D 都最多只记住了某一张质量不比 i 差的另一张图片 Ki。”这么一句话
所以每个点入度就为1,就是一棵树了。

当然先要判断一下有没有环,环的话就输出0 否则就treedp 乘个组合数什么的就好了
如果要看详细题解的推荐这个:传送门

留个代码

#include<bits/stdc++.h>
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
typedef long long LL;
const int N=105,mod=1e9+7;
inline LL read(){
    char ch=getchar(); LL x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
    return x*f;
}
struct node{int y,next;}a[N]; int len,first[N];
void ins(int x,int y){
    a[++len]=(node){y,first[x]},first[x]=len;
}
int c[N][N],fa[N],ax[N],ay[N],al;
int fi(int x){return fa[x]==x?x:fa[x]=fi(fa[x]);}
bool v[N],ok;
void fc(int x){
    v[x]=1;
    for(int k=first[x];k;k=a[k].next){
        if(v[a[k].y]){ok=0; return;}
        fc(a[k].y);
    }
}
int siz[N],d[N],f[N][N],g[N];
void dfs(int x){
    bool o=1;
    for(int k=first[x];k;k=a[k].next){
        int y=a[k].y; dfs(y);
        if(o){
            siz[x]=siz[y],o=0;
            for(int i=1;i<=siz[x];++i)f[x][i]=f[y][i];
        }
        else{
            me(g,0);
            for(int i=1;i<=siz[x];++i)if(f[x][i])
            for(int j=1;j<=siz[y];++j)if(f[y][j])
            for(int p=max(i,j);p<=i+j;++p)
              g[p]=(g[p]+1ll*f[x][i]*f[y][j]%mod*c[p][i]%mod*c[i][j-p+i]%mod)%mod;
            siz[x]+=siz[y];
            for(int i=1;i<=siz[x];++i)f[x][i]=g[i];
        }
    }
    if(x){
        siz[x]++;
        if(o)f[x][1]=1;
        else for(int i=siz[x];i;--i)f[x][i]=f[x][i-1];
    }
}
int main()
{
    int n=read(),m=read(),i,j;
    for(i=1;i<=n;++i)fa[i]=i;
    for(i=0;i<=n;++i)
        for(c[i][0]=j=1;j<=i;++j) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    al=0;
    for(int i=1;i<=m;++i){
        int x=read(); char c; scanf("\n%c",&c);
        int y=read();
        if(c=='=') x=fi(x),y=fi(y),fa[x]=y;
        else ax[++al]=x,ay[al]=y;
    }
    for(int i=1;i<=al;++i){
        int x=fi(ax[i]),y=fi(ay[i]);
        if(x==y) return printf("0\n"),0;
        ins(x,y),d[y]++;
    }
    ok=1;
    for(int i=1;i<=n;++i) if(!d[i])fc(i);
    if(!ok) return printf("0\n"),0;
    for(int i=1;i<=n;++i) if(!d[i] && fi(i)==i)ins(0,i);
    dfs(0); int ans=0;
    for(int i=1;i<=n;++i) ans=(ans+f[0][i])%mod;
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值