【LOJ】#2117. 「HNOI2015」实验比较
2018-09-13 18:49
357 查看
题解
把所有=的点连起来,一个图合法肯定它是一个有向树森林
我们新建一个点,把这个点和其他所有树的树根连起来
定义\(dp[u][j]\)表示第u个点长度为j的序列的方案数
转移方法是
\(dp[u][j] += g[k] \cdot dp[v][h] \cdot \binom{j}{k} \cdot \binom{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('\n') #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 [i]); out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); return 0; }
相关文章推荐
- [HNOI 2015]实验比较
- BZOJ 4013: [HNOI2015]实验比较
- bzoj4013: [HNOI2015]实验比较
- bzoj4013: [HNOI2015]实验比较
- bzoj4013[HNOI2015]实验比较
- 【BZOJ】4013: [HNOI2015]实验比较
- bzoj 4013: [HNOI2015]实验比较
- BZOJ 4013: [HNOI2015]实验比较
- 【bzoj4013】[HNOI2015]实验比较 树形dp+组合数学
- 【bzoj4013】 HNOI2015—实验比较
- [HNOI2015]实验比较
- BZOJ4013: [HNOI2015]实验比较
- BZOJ4013 : [HNOI2015]实验比较
- BZOJ4013: [HNOI2015]实验比较
- HNOI2015 实验比较
- 【BZOJ 4013】[HNOI2015]实验比较
- BZOJ 4013 【HNOI2015】 实验比较
- bzoj 4013: [HNOI2015]实验比较 (树形DP+组合数学)
- bzoj 4013: [HNOI2015]实验比较
- [BZOJ4013][HNOI2015]实验比较(树形DP+组合数学)