1. 程式人生 > >【BZOJ3659】Which Dreamed It【有向圖歐拉回路計數】【matrix tree定理】【BEST定理】【高斯消元】

【BZOJ3659】Which Dreamed It【有向圖歐拉回路計數】【matrix tree定理】【BEST定理】【高斯消元】

定理題...

/* Think Thank Thunk */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxn = 105, p = 1000003;

int n, fact[200005], A[maxn][maxn], du[maxn];

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}

inline int qpow(int a, int n) {
	int res = 1;
	for(; n; n >>= 1, a = (LL)a * a % p) if(n & 1) res = (LL)res * a % p;
	return res;
}

inline int gauss() {
	for(int i = 1; i < n; i++) {
		if(!A[i][i]) for(int j = i + 1; j < n; j++) if(A[j][i]) {
			for(int k = i; k < n; k++) swap(A[i][k], A[j][k]);
			break;
		}

		int rev = qpow(A[i][i], p - 2);
		for(int j = i + 1; j < n; j++) if(A[j][i]) {
			int t = (LL)A[j][i] * rev % p;
			for(int k = i; k < n; k++) A[j][k] = (A[j][k] - (LL)A[i][k] * t % p + p) % p;
		}
	}
	int res = 1;
	for(int i = 1; i < n; i++) res = (LL)res * A[i][i] % p;
	return res;
}

int main() {
	fact[0] = 1;
	for(int i = 1; i <= 200000; i++) fact[i] = (LL)fact[i - 1] * i % p;

	while(1) {
		n = iread();
		if(!n) break;

		for(int i = 1; i <= n; i++) {
			du[i] = 0;
			for(int j = 1; j <= n; j++) A[i][j] = 0;
		}

		for(int i = 1; i <= n; i++) {
			du[i] = iread();
			for(int j = 1; j <= du[i]; j++) {
				int x = iread();
				if(x != i) A[i][x]--, A[i][i]++;
			}
		}

		if(n == 1 && du[1] == 0) {
			printf("1\n");
			continue;
		}

		for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++)
			(A[i][j] += p) %= p;

		int ans = (LL)gauss() * du[1] % p;
		for(int i = 1; i <= n; i++) ans = (LL)ans * fact[du[i] - 1] % p;
		printf("%d\n", ans);
	}
	return 0;
}