//Let's join Kaede Takagaki Fan Club !! #include #include #include using namespace std; typedef long long ll; typedef pair P; typedef pair P1; typedef pair P2; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 1000000000 #define fi first #define sc second #define rep(i,x) for(int i=0;i void dmp(T a){ rep(i,a.size()) cout << a[i] << " "; cout << endl; } template bool chmax(T&a, T b){ if(a < b){ a = b; return 1; } return 0; } template bool chmin(T&a, T b){ if(a > b){ a = b; return 1; } return 0; } template void g(T &a){ cin >> a; } template void o(const T &a,bool space=false){ cout << a << (space?' ':'\n'); } //ios::sync_with_stdio(false); const int mod = 1000000007; template void add(T&a,T b){ a+=b; if(a >= mod) a-=mod; } template T mul(T a, T b){ return (T) ((ll)(a) * b % mod); } ll modpow(ll x,ll n){ ll res=1; while(n>0){ if(n&1) res=res*x%mod; x=x*x%mod; n>>=1; } return res; } template vectorBerlekampMassey(vectorx){ vectorls,cur; T lf,ld; rep(i,x.size()){ T t = 0; for(int j=0;jc(i-lf-1); c.pb(k); rep(j,ls.size()) c.pb((ll)-ls[j]*k%mod); if(c.size() < cur.size()) c.resize(cur.size()); rep(j,cur.size()){ c[j]=(c[j]+cur[j]); while(c[j] < 0) c[j] += mod; while(c[j] >= mod) c[j] -= mod; } if(i-lf+(int)(ls.size()) >= (int)(cur.size())){ ls = cur, lf = i, ld = (t-x[i])%mod; } cur = c; } rep(i,cur.size()) cur[i] = (cur[i]%mod+mod)%mod; return cur; } vectorrand_vec(int n, int seed = -1){ if(seed == -1) seed = n; mt19937 mt(seed); vectorret(n); rep(i, n) ret[i] = mt() % (mod-1) + 1; return ret; } int dot(vector&a, vector&b){ int ret = 0; rep(i, a.size()) add(ret, mul(a[i], b[i])); return ret; } //今回はunmarkのcellはM_(i,j) = -v[j]なので注意 vectorfind_min_poly(int n, vectormat, vector&v){ srand((unsigned)time(NULL)); vectorM = rand_vec(n), R = rand_vec(n, rand()); vectortest(2*n); rep(i, 2*n){ test[i] = dot(M, R); vectornw(n); rep(j, n) add(nw[0], mul(M[j], mod-v[j])); rep(i, n-1) nw[i+1] = nw[0]; rep(j, mat.size()){ int r = mat[j].sc.fi, c = mat[j].sc.sc; add(nw[r], mul((v[c]+mat[j].fi), M[c])); } swap(nw, M); } vectorret = BerlekampMassey(test); for(int i=0;imat){ if(n <= 0) return 1; srand((unsigned)time(NULL)); while(1){ vectorM = rand_vec(n, rand()); vectorcp = mat; rep(j, mat.size()){ int r = mat[j].sc.fi, c = mat[j].sc.sc; cp[j].fi = mul(cp[j].fi, M[c]); } vectorret = find_min_poly(n, cp, M); if(ret[0] == 0) return 0; if(ret.size() != n+1) continue; int ans = (n%2 == 0 ? ret[0] : mod-ret[0]); int d1 = 1; for(auto a:M) d1 = mul(d1, a); d1 = modpow(d1, mod-2); return (mul(ans, d1)%mod+mod)%mod; } } int n, m; int indeg[4005], outdeg[4005]; int cnt[4005][4005]; bool cir; ll F[4005]; int main(){ scanf("%d%d", &n, &m); if(m == n*n){ puts("1"); return 0; } repn(i, n) repn(j, n){ cnt[i][j] ++; indeg[j] ++; outdeg[i] ++; } rep(i, m){ int a, b; scanf("%d%d", &a, &b); cnt[a][b] --; indeg[b] --; outdeg[a] --; } int bad = 0, idi, ido; repn(i, n){ if(outdeg[i]-indeg[i] == 1) { bad ++; ido = i; } else if(outdeg[i]-indeg[i] == -1) { idi = i; } else if(indeg[i] != outdeg[i]) bad = 61471; } if(bad == 0) cir = 1; else if(bad > 1){ puts("0"); return 0; } else{ cnt[idi][ido]++; indeg[ido]++; outdeg[idi]++; } vectormat; vectorconv(n+2), rev(n+2); int sz = 0; repn(i, n){ if(indeg[i]){ rev[sz] = i; conv[i] = sz++; } } rep(i, sz-1) rep(j, sz-1){ if(i != j){ if(cnt[rev[i]][rev[j]] != 1) mat.pb(mp(-cnt[rev[i]][rev[j]], mp(i, j))); } else{ mat.pb(mp(indeg[rev[i]]-cnt[rev[i]][rev[i]], mp(i, i))); } } int ctree = calc_det(sz-1, mat); if(ctree == 0){ puts("0"); return 0; } F[0] = 1; for(int i=1;i<4005;i++) F[i] = F[i-1] * i % mod; repn(i,n) if(indeg[i]) ctree = mul(ctree, (int)F[indeg[i]-1]); if(cir) ctree = mul(ctree, n*n-m); printf("%d\n", ctree); }