#include #include #include #include #include #include #include using namespace std; const int MOD = 1000*1000*1000 + 7; const int MAX_N = 50 + 2; const int MAX_T = 50 + 2; const int MAX_Q = 200000 + 2; const int MAX_K_INIT = 10000 + 2; const long double PI = acos(-1.0); const int MAGIC = 500; int MAX_K = 100; struct Tuple { int L, R, K, index; Tuple(){}; Tuple(int _L, int _R, int _K):L(_L), R(_R), K(_K){}; bool operator < (Tuple instance) const { if (this -> L != instance.L) return (this -> L < instance.L); if (this -> R != instance.R) return this -> R < instance.R; return this -> K > instance.K; } } query[MAX_Q]; int T, Q, N[MAX_T]; int A[MAX_T][MAX_N][MAX_N]; int trace[MAX_T][MAX_K_INIT]; int factorial[MAX_K_INIT], inverseFactorial[MAX_K_INIT], inverseNumbers[MAX_K_INIT]; int detPolynomial[MAX_T][MAX_N]; int answer[MAX_Q]; int G[MAX_K_INIT << 2]; int D[MAX_T][MAX_T][MAX_K_INIT]; int S[MAX_K_INIT << 2]; inline void input(); inline int auxilaryInfo(); inline void createTraces(); inline void createProdTraces(); inline void debugPrint(); inline void Process(); inline void add(int &a, int b); inline int mul(int &a, int b); /** * template fast fourier transform * **/ #define sz(C) ((int) (C).size()) #define forn(i, n) for (int i = 0; i < (int) n; ++i) #define ford(i, n) for (int i = ((int) n) - 1; i >= 0; --i) typedef vector vi; void addmod(int& x, int y, int mod) { (x += y) >= mod && (x -= mod); } int mulmod(int x, int y, int mod) { return x * 1ll * y % mod; } #define ld double namespace FFT { struct cd { ld a, b; cd(ld a, ld b) : a(a), b(b) {} cd(ld x = 0) : a(x), b(0) {} ld real() const { return a; } void operator += (const cd& other) { a += other.a; b += other.b; } void operator -= (const cd& other) { a -= other.a; b -= other.b; } void operator *= (const cd& other) { long double a1 = a * other.a - b * other.b; long double b1 = a * other.b + b * other.a; a = a1; b = b1; } friend cd operator * (const cd& x, const cd& y) { cd r = x; r *= y; return r; } friend cd operator + (const cd& x, const cd& y) { cd r = x; r += y; return r; } friend cd operator - (const cd& x, const cd& y) { cd r = x; r -= y; return r; } void operator /= (ld c) { a /= c; b /= c; } }; typedef vector vcd; int LOG = 15; int N = 1 << LOG; const int N_INIT = 1 << 15; int rev[N_INIT]; cd root_[N_INIT]; inline cd root(int k, int n) { return root_[k * (N / n)]; } void precalc(int MAX) { LOG = 0; while ((1 << LOG) < MAX) LOG ++; LOG ++; N = 1 << LOG; rev[0] = 0; int hb = -1; for (int i = 1; i < N; ++i) { if ((i & (i - 1)) == 0) { ++hb; } rev[i] = rev[i ^ (1 << hb)] | (1 << (LOG - hb - 1)); } forn(i, N) { ld ang = PI * i * 2.0 / N; root_[i] = cd(cosl(ang), sinl(ang)); } } void fft_rec(cd* a, int n) { if (n == 1) { return; } fft_rec(a, n / 2); fft_rec(a + n / 2, n / 2); forn(k, n / 2) { cd w = root(k, n); cd x = a[k]; cd y = w * a[k + n / 2]; a[k] = x + y; a[k + n / 2] = x - y; } } void fft(vcd& a) { int n = sz(a); vcd na(n, cd(0, 0)); forn(i, n) na[i] = a[rev[i]]; na.swap(a); fft_rec(&a[0], n); } void fft_inv(vcd& a) { fft(a); int n = sz(a); reverse(a.begin() + 1, a.end()); forn(i, n) { a[i] /= n; } } vi mult(const vi& a, const vi& b) { // TimeStamp t("mult"); vcd A(N, cd(0, 0)); vcd B(N, cd(0, 0)); forn(i, sz(a)) A[i] = a[i]; forn(i, sz(b)) B[i] = b[i]; fft(A); fft(B); forn(i, N) A[i] *= B[i]; fft_inv(A); vi c(N, 0); forn(i, N) c[i] = ((long long) (A[i].real() + 0.5)) % MOD; return c; } vi multmod(const vi& a, const vi& b) { // a = a0 + sqrt(MOD) * a1 // a = a0 + base * a1 int base = (int) sqrtl(MOD); vi a0(sz(a)), a1(sz(a)); forn(i, sz(a)) { a0[i] = a[i] % base; a1[i] = a[i] / base; assert(a[i] == a0[i] + base * a1[i]); } vi b0(sz(b)), b1(sz(b)); forn(i, sz(b)) { b0[i] = b[i] % base; b1[i] = b[i] / base; assert(b[i] == b0[i] + base * b1[i]); } vi a01 = a0; forn(i, sz(a)) { addmod(a01[i], a1[i], MOD); } vi b01 = b0; forn(i, sz(b)) { addmod(b01[i], b1[i], MOD); } vi C = mult(a01, b01); // 1 vi a0b0 = mult(a0, b0); // 2 vi a1b1 = mult(a1, b1); // 3 vi mid = C; forn(i, N) { addmod(mid[i], -a0b0[i] + MOD, MOD); addmod(mid[i], -a1b1[i] + MOD, MOD); } vi res = a0b0; forn(i, N) { addmod(res[i], mulmod(base, mid[i], MOD), MOD); } base = mulmod(base, base, MOD); forn(i, N) { addmod(res[i], mulmod(base, a1b1[i], MOD), MOD); } return res; } }; inline void add(int &a, int b) { if ((a += b) >= MOD) a -= MOD; if (a < 0) { a %= MOD; a += MOD; } } inline int mul(int &a, int b) { if (b == -1) a = -a; else a = (a * 1ll * b) % MOD; if (a < 0) { a += MOD; } return a; } inline void DP(int L, int R) { if (MAX_K > MAGIC) { vector A(MAX_K), B(MAX_K); for (int k = 0; k < MAX_K; k ++) { A[k] = (k & 1)?MOD - inverseFactorial[k]:inverseFactorial[k]; B[k] = D[L][R][k] * 1ll * inverseFactorial[k] % MOD; } vector C = FFT::multmod(A, B); for (int k = 0; k < MAX_K; k ++) G[k] = C[k]; } else { for (int i = 0; i < MAX_K; i ++) { int auxB = D[L][R][i] * 1ll * inverseFactorial[i] % MOD; for (int j = 0; j + i < MAX_K; j ++) { add(G[i + j], auxB * 1ll * ((j & 1)?MOD - inverseFactorial[j]:inverseFactorial[j]) % MOD); } } } S[0] = G[0] = 0; for (int k = 1; k < MAX_K; k ++) { G[k] = G[k] * 1ll * factorial[k] % MOD; S[k] = G[k]; G[k] = 0; add(S[k], S[k - 1]); } } int main() { input(); auxilaryInfo(); createTraces(); createProdTraces(); Process(); for (int i = 1; i <= Q; i ++) { printf("%d\n", answer[i]); } //system("pause"); } inline void debugPrint() { for (int graph = 1; graph <= T; graph ++) { cout << graph << " - Graph statistic\n"; cout << "Matrix: " << endl; for (int i = 1; i <= N[graph]; i ++) { for (int j = 1; j <= N[graph]; j ++) cout << A[graph][i][j] << " "; cout << endl; } cout << "Traces: \n"; for (int i = 0; i <= N[graph] << 1; i ++) cout << i << "-th: " << trace[graph][i] << endl; cout << "detPolynomial (from smallest to largest ind) \n"; for (int i = 0; i <= N[graph]; i ++) cout << detPolynomial[graph][i] << " "; cout << endl; } } int binaryPower(int x, long long degree) { int result = 1; for (; degree > 0; degree >>= 1) { if (degree & 1) mul(result, x); mul(x,x); } return result; } inline void Process() { if (MAX_K > MAGIC) { FFT::precalc(MAX_K); } sort(query + 1, query + Q + 1); for (int i = 1; i <= Q; i ++) { if (i == 1 || query[i].L != query[i - 1].L || query[i].R != query[i - 1].R) DP(query[i].L, query[i].R); answer[query[i].index] = S[query[i].K]; } } inline void createProdTraces() { for (int graphL = 1; graphL <= T; graphL ++) { for (int graphR = graphL; graphR <= T; graphR ++) { for (int i = 0; i < MAX_K; i ++) { if (graphL == graphR) D[graphL][graphR][i] = trace[graphL][i]; else D[graphL][graphR][i] = (D[graphL][graphR-1][i] * 1ll * trace[graphR][i]) % MOD; } } } } int current[MAX_N][MAX_N]; int temporaryMatrix[MAX_N][MAX_N]; inline void preComputeTraces() { for (int graph = 1; graph <= T; graph ++) { trace[graph][0] = N[graph]; for (int i = 1; i <= N[graph]; i ++) { for (int j = 1; j <= N[graph]; j ++) temporaryMatrix[i][j] = current[i][j] = 0; temporaryMatrix[i][i] = 1; } for (int degree = 1; degree <= N[graph]; degree ++) { for (int i = 1; i <= N[graph]; i ++) for (int k = 1; k <= N[graph]; k ++) if (temporaryMatrix[i][k]) for (int j = 1; j <= N[graph]; j ++) if (A[graph][k][j]) add(current[i][j], temporaryMatrix[i][k]); for (int i = 1; i <= N[graph]; i ++) for (int j = 1; j <= N[graph]; j ++) { temporaryMatrix[i][j] = current[i][j]; current[i][j] = 0; } trace[graph][degree] = 0; for (int i = 1; i <= N[graph]; i ++) add(trace[graph][degree], temporaryMatrix[i][i]); } } } int e[MAX_N]; inline void createDetPolynomial() { for (int graph = 1; graph <= T; graph ++) { e[0] = 1; for (int i = 1; i <= N[graph]; i ++) { int sign = 1; e[i] = 0; for (int j = i - 1; j >= 0; j --, sign *= -1) { int toAdd = (e[j] * 1ll * trace[graph][i-j]) % MOD; if (sign == -1) mul(toAdd, -1); add(e[i], toAdd); } mul(e[i], inverseNumbers[i]); } detPolynomial[graph][N[graph]] = 1; for (int i = 1, sign = -1; i <= N[graph]; i ++, sign = -sign) { if (sign == -1) mul(e[i], -1); detPolynomial[graph][N[graph] - i] = e[i]; } } } inline void createTraces() { for (int graph = 1; graph <= T; graph ++) { for (int i = 1; i <= N[graph]; i ++) A[graph][i][i] ++; } preComputeTraces(); createDetPolynomial(); for (int graph = 1; graph <= T; graph ++) { for (int degree = N[graph] + 1; degree < MAX_K; degree ++) { trace[graph][degree] = 0; for (int i = 0; i < N[graph]; i ++) { int current = (trace[graph][i + degree - N[graph]] * 1ll * detPolynomial[graph][i]) % MOD; add(trace[graph][degree], current); } mul(trace[graph][degree], -1); } } } inline int auxilaryInfo() { factorial[0] = 1; for (int i = 1; i < MAX_K; i ++) { factorial[i] = (factorial[i - 1] * 1ll * i) % MOD; } for (int i = 0; i < MAX_K; i ++) { inverseFactorial[i] = binaryPower(factorial[i], MOD - 2); if (i) inverseNumbers[i] = binaryPower(i, MOD - 2); } } inline void input() { scanf("%d", &T); assert(T >= 1 && T <= 50); for (int i = 1; i <= T; i ++) { for (int j = 0; j < MAX_N; j ++) for (int k = 0; k < MAX_N; k ++) A[i][j][k] = 0; for (int j = 0; j < MAX_K; j ++) trace[i][j] = 0; for (int j = 0; j < MAX_N; j ++) detPolynomial[i][j] = 0; int E; scanf("%d %d", &N[i], &E); assert(N[i] >= 1 && N[i] <= 50); assert(0 <= E && E <= N[i] * (N[i] - 1) / 2); for (int j = 1; j <= E; j ++) { int v, u; scanf("%d %d", &v, &u); assert(v != u); assert(1 <= v && v <= N[i]); assert(1 <= u && u <= N[i]); A[i][v][u] = A[i][u][v] = 1; } } scanf("%d", &Q); assert(1 <= Q && Q <= 200000); for (int i = 1; i <= Q; i ++) { scanf("%d %d %d", &query[i].L, &query[i].R, &query[i].K); assert(1 <= query[i].L && query[i].L <= query[i].R && query[i].R <= T); assert(0 <= query[i].K && query[i].K <= 10000); MAX_K = max(MAX_K, query[i].K); query[i].index = i; } MAX_K += 2; }