zoukankan      html  css  js  c++  java
  • 【LOJ】#2117. 「HNOI2015」实验比较

    题解

    把所有=的点连起来,一个图合法肯定它是一个有向树森林

    我们新建一个点,把这个点和其他所有树的树根连起来

    定义(dp[u][j])表示第u个点长度为j的序列的方案数
    转移方法是
    (dp[u][j] += g[k] cdot dp[v][h] cdot inom{j}{k} cdot inom{k}{h - j + k})
    (g[k])是我们记录之前儿子合并的序列为k的方案数
    就是我们确定目标序列的长度为(j)后,选(k)个位置放第一个序列,在这(k)个位置中再选(h - j + k)个作为第二个序列和第一个序列重合的部分,和之前的空位一起放第二个序列

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define MAXN 105
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef long double db;
    typedef unsigned int u32;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const int MOD = 1000000007;
    int N,M,id[MAXN],cnt;
    int u[MAXN],v[MAXN],f[MAXN],ind[MAXN];
    char ch[MAXN][5];
    int vis[MAXN],C[MAXN][MAXN],dp[MAXN][MAXN],siz[MAXN],g[MAXN],s[MAXN];
    struct node {
        int next,to;
    }E[MAXN * 2];
    int sumE,head[MAXN];
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void add(int u,int v) {
        E[++sumE].next = head[u];
        E[sumE].to = v;
        head[u] = sumE;
    }
    int getf(int u) {
        return f[u] == u ? u : f[u] = getf(f[u]);
    }
    bool check(int u) {
        vis[u] = 1;
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	if(!vis[v]) {if(!check(v)) return false;}
    	if(vis[v] == 1) return false;
        }
        vis[u] = 2;
        return true;
    }
    void Init() {
        read(N);read(M);
        for(int i = 1 ; i <= N ; ++i) f[i] = i;
        for(int i = 1 ; i <= M ; ++i) {
    	read(u[i]);scanf("%s",ch[i]);read(v[i]);
    	if(ch[i][0] == '=') {
    	    f[getf(u[i])] = getf(v[i]);
    	}
        }
        for(int i = 1 ; i <= N ; ++i) {
    	if(!id[getf(i)]) id[getf(i)] = ++cnt;
        }
        for(int i = 1 ; i <= M ; ++i) {
    	if(ch[i][0] == '<') {
    	    add(id[getf(u[i])],id[getf(v[i])]);
    	    ind[id[getf(v[i])]]++;
    	}
        }
        N = cnt + 1;
        for(int i = 1 ; i <= cnt ; ++i) if(!ind[i]) add(N,i);
        C[0][0] = 1;
        for(int i = 1 ; i <= 101 ; ++i) {
    	C[i][0] = 1;
    	for(int j = 1 ; j <= i ; ++j) {
    	    C[i][j] = inc(C[i - 1][j],C[i - 1][j - 1]);
    	}
        }
    }
    void dfs(int u) {
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	dfs(v);
        }
        memset(g,0,sizeof(g));
        g[0] = 1;
        for(int i = head[u] ; i ; i = E[i].next) {
    	int v = E[i].to;
    	for(int j = 0 ; j <= siz[u] + siz[v] ; ++j) {
    	    s[j] = 0;
    	    for(int k = 0 ; k <= siz[v] ; ++k) {
    		if(k > j) break;
    		for(int h = 0 ; h <= siz[u] ; ++h) {
    		    if(h > j) break;
    		    s[j] = inc(s[j],mul(mul(dp[v][k],g[h]),mul(C[j][k],C[k][h - j + k])));
    		}
    	    }
    	}
    	for(int j = 0 ; j <= siz[u] + siz[v] ; ++j) g[j] = s[j];
    	siz[u] += siz[v];
        }
        ++siz[u];
        for(int j = 1 ; j <= siz[u] ; ++j) dp[u][j] = g[j - 1];
    }
    void Solve() {
        for(int i = 1 ; i <= N ; ++i) {
    	if(!vis[i] && !check(i)) {puts("0");return;}
        }
        dfs(N);
        int ans = 0;
        for(int i = 0 ; i <= N ; ++i) ans = inc(ans,dp[N][i]);
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    算法训练 接水问题
    算法训练 数组排序去重
    算法训练 A+B Problem
    算法训练 采油区域
    算法训练 会议中心
    JS高级
    JS基础操作
    JavaScript入门(基础)
    表格与表单
    音频与视频
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9642357.html
Copyright © 2011-2022 走看看