题意:给定由N个与非门组成的树,有若干个与非门无论什么输入,输出都是1或0,求输出答案错误的输入方案数。
分析:每个点维护一个矩阵,其中a表示该点输出为0且该输出是错误的方案数,b表示该点输出为0且该输出是正确的方案数,c表示该点输出为1且该输出是错误的方案数,d表示该点输出为1且该输出是正确的方案数。
简称为错0,错1,对0,对1.
可以得到
错0 = 左错1*右对1+左对1*右错1+左错1*右错1
错1 = 左错0*右错0+左错0*右对1+左对1*右错0
对于一个点的两个儿子用和表示。
那么
若这个点的与非门是坏的,就把错1加到对0,对1加到错0,或者是错0加到对1,对0加到错1。
然后就做完了,最后答案就是根节点的a+c。
#include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; long long dp[100004][2][2];//0 1 wa ac pair<int, int> p[100004]; int wa[100004]; void dfs(int u) { if (u == 0)return; int l = p[u].first; int r = p[u].second; dfs(l); dfs(r); dp[u][0][0] = dp[l][0][1] * dp[r][0][1] % mod + dp[l][0][1] * dp[r][1][1] % mod + dp[l][1][1] * dp[r][0][1] % mod; dp[u][0][1] = dp[l][0][0] * dp[r][0][0] % mod + dp[l][0][0] * dp[r][1][1] % mod + dp[l][1][1] * dp[r][0][0] % mod; dp[u][0][1] %= mod; dp[u][0][0] %= mod; long long lone = (dp[l][0][1] + dp[l][1][1]) % mod; long long lzero = (dp[l][0][0] + dp[l][1][0]) % mod; long long rone = (dp[r][0][1] + dp[r][1][1]) % mod; long long rzero = (dp[r][0][0] + dp[r][1][0]) % mod; long long one = lone * rzero % mod + lzero * rone % mod + lzero * rzero % mod; one %= mod; long long zero = lone * rone % mod; dp[u][1][0] = (zero - dp[u][0][0] + mod) % mod; dp[u][1][1] = (one - dp[u][0][1] + mod) % mod; if (wa[u] == 1) { dp[u][0][1] += dp[u][1][0]; dp[u][1][1] += dp[u][0][0]; dp[u][1][0] = dp[u][0][0] = 0; dp[u][0][1] %= mod; dp[u][1][1] %= mod; } else if (wa[u] == 0) { dp[u][0][0] += dp[u][1][1]; dp[u][1][0] += dp[u][0][1]; dp[u][1][1] = dp[u][0][1] = 0; dp[u][0][0] %= mod; dp[u][1][0] %= mod; } } int main() { int n; int x, y, f; scanf("%d", &n); dp[0][0][0] = dp[0][0][1] = 0; dp[0][1][0] = dp[0][1][1] = 1; for (int i = 1; i <= n; ++i) { scanf("%d%d%d", &x, &y, &f); p[i].first = x; p[i].second = y; wa[i] = f; } dfs(1); cout << (dp[1][0][0] + dp[1][0][1]) % mod << endl; }