【LOJ】#2117. 「HNOI2015」實驗比較
阿新 • • 發佈:2018-09-13
max spa get signed struct size space add 一個
題解
把所有=的點連起來,一個圖合法肯定它是一個有向樹森林
我們新建一個點,把這個點和其他所有樹的樹根連起來
定義\(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[N][i]); out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); return 0; }
【LOJ】#2117. 「HNOI2015」實驗比較