#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"

using namespace std;

using ll = int64_t;
using db = double;
using ld = long double;
using vi = vector<int>;
using vl = vector<ll>;
using vvi = vector<vector<int>>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vpii = vector<pii>;
using vpll = vector<pll>;

constexpr char newl = '\n';
constexpr double eps = 1e-10;

#define FOR(i,a,b) for (int i = (a); i < (b); i++)
#define F0R(i,b) FOR(i,0,b)
#define RFO(i,a,b) for (int i = ((b)-1); i >=(a); i--)
#define RF0(i,b) RFO(i,0,b)
#define show(x) cout << #x << " = " << (x) << '\n';
#define rng(a) a.begin(),a.end()
#define rrng(a) a.rbegin(),a.rend()
#define sz(x) (int)(x).size()
#define YesNo {cout<<"Yes";}else{cout<<"No";}
#define YESNO {cout<<"YES";}else{cout<<"NO";}
#define v(T) vector<T>
#define vv(T) vector<vector<T>>

template<typename T1, typename T2> inline void chmin(T1& a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> inline void chmax(T1& a, T2 b) { if (a < b) a = b; }
template<class T> bool lcmp(const pair<T, T>& l, const pair<T, T>& r) {
  return l.first < r.first;
}
template<class T> istream& operator>>(istream& i, v(T)& v) {
  F0R(j, sz(v)) i >> v[j];
  return i;
}
template<class A, class B> istream& operator>>(istream& i, pair<A, B>& p) {
  return i >> p.first >> p.second;
}
template<class A, class B, class C> istream& operator>>(istream& i, tuple<A, B, C>& t) {
  return i >> get<0>(t) >> get<1>(t) >> get<2>(t);
}
template<class T> ostream& operator<<(ostream& o, const pair<T, T>& v) {
  o << "(" << v.first << "," << v.second << ")";
  return o;
}
template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
  F0R(i, v.size()) {
    o << v[i] << ' ';
  }
  o << newl;
  return o;
}
template<class T> ostream& operator<<(ostream& o, const set<T>& v) {
  for (auto e : v) {
    o << e << ' ';
  }
  o << newl;
  return o;
}
template<class T1, class T2> ostream& operator<<(ostream& o, const map<T1, T2>& m) {
  for (auto& p : m) {
    o << p.first << ": " << p.second << newl;
  }
  o << newl;
  return o;
}

#if 1

#ifdef __GNUC__
#define popcount __builtin_popcountll
#else
constexpr int popcount(ll x)
{
  x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
  x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
  x = (x & 0x0f0f0f0f0f0f0f0f) + (x >> 4 & 0x0f0f0f0f0f0f0f0f);
  x = (x & 0x00ff00ff00ff00ff) + (x >> 8 & 0x00ff00ff00ff00ff);
  x = (x & 0x0000ffff0000ffff) + (x >> 16 & 0x0000ffff0000ffff);
  return (int)((x & 0x00000000ffffffff) + (x >> 32 & 0x00000000ffffffff));
}
#endif

struct Cst {
  int x, y, z;
  bool operator<(const Cst& v) const {
    return x < v.x;
  }
};

// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N, M; cin >> N >> M;
  v(Cst) cs(M);
  vv(Cst) ds(N + 1);
  F0R(i, M) {
    cin >> cs[i].x >> cs[i].y >> cs[i].z;
    ds[cs[i].x].push_back(cs[i]);
  }
  vl dp(1 << N);  // 既に並べた数が 集合i のときの場合の数
  dp[0] = 1;
  FOR(b, 1, 1 << N) {
    F0R(i, N) {
      if ((b >> i) & 1) {
        dp[b] += dp[b ^ (1 << i)];
      }
    }
    int pc = popcount(b);
    for (auto [x, y, z] : ds[pc]) {
      int a = b & ((1 << y) - 1);
      if (popcount(a) > z) {
        dp[b] = 0;
        break;
      }
    }
  }
  cout << dp[(1 << N) - 1] << newl;
}
#endif

#include <bits/stdc++.h>
using namespace std;
 
#define all(x) x.begin(), x.end()
#define sz(x) (int) x.size()
#define pb push_back
#define endl '\n'
#define snd second
#define fst first
#define fastio cin.tie(NULL),cout.sync_with_stdio(true)
 
typedef long long int ll;
typedef unsigned long long int ull;
typedef vector <int> vi;
typedef pair <int,int> ii;
const int mod = 1e9 + 7;
const ll INF = 3e18;
const double EPSILON = 1e-9;
const int N = 200005;
struct ST{
    int pos, qt, val;
};
bool valid[1<<19];
int n, m;
ll dp[1<<19];
ll solve(int msk){
    if(msk == (1<<n)-1)
        return 1;
    if(dp[msk] != -1)
        return dp[msk];
    ll ans = 0;
    for(int j = 0; j < n; j++){
        if(!(msk&(1<<j)) and valid[msk+(1<<j)]){
            ans += solve(msk+(1<<j));
        }
    }
    return dp[msk] = ans;
}
int main(){
    fastio;
    memset(dp, -1, sizeof(dp));
    cin >> n >> m;
    ST v[m];
    for(int i = 0; i < m; i++){
        cin >> v[i].pos >> v[i].val >> v[i].qt;
    }
    for(int msk = 0; msk < (1<<n); msk++){
        int x = __builtin_popcount(msk);
        vi sum(n+1);
        for(int i = 0; i < n; i++){
            if(msk&(1<<i)){
                sum[i+1]++;
            }
            sum[i+1] += sum[i];
        }
        bool flag = true;
        for(int j = 0; j < m; j++){
            if(v[j].pos < x)continue;
            if(sum[v[j].val] > v[j].qt)
                flag = false;
        }
        valid[msk] = flag;
    }
    cout << solve(0) << "\n";
    return 0;
}
