• 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
    ");
        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
    ",ans);
        }
        
        return 0;
    }
  • 相关阅读:
    列"xx"不在表Table中
    asp.net中自定义验证控件
    ASP.NET母版与内容页相对路径的问题
    html点小图看大图最快捷的方法
    ThinkCMF的跳转303 404等页面的方法
    关于ThinkCMF自带插件上传不了图片的解决方法
    js中百分比运算,大型数据会算错
    数据库价格汇总查询的方法
    信息资源5
    操作系统概论
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10156082.html
Copyright © 2020-2023  润新知