#include <bits/stdc++.h>   template <int MOD>   struct Integral {     int v_ = 0;     template <typename T>     Integral(T v) : v_(norm(v)) {       static_assert(std::is_integral<T>::value,  input should be an integral. );     }     Integral() = default;     ~Integral() = default;     template <typename T>     T norm(T v) const {       if (v >= MOD) v -= MOD;       if (v < 0) v += MOD;       if (v >= MOD || v < 0) v = (v % MOD + MOD) % MOD;       return v;     }     int val() const { return v_; }     Integral operator+(const Integral& rhs) const {       return Integral(val() + rhs.val());     }     Integral operator-(const Integral& rhs) const {       return Integral(val() - rhs.val());     }     Integral operator*(const Integral& rhs) const {       return Integral(val() * 1LL * rhs.val());     }     Integral operator/(const Integral& rhs) const { return *this * rhs.inv(); }     Integral& operator+=(const Integral& rhs) { return *this = *this + rhs; }     Integral& operator-=(const Integral& rhs) { return *this = *this - rhs; }     Integral& operator*=(const Integral& rhs) { return *this = *this * rhs; }     Integral& operator/=(const Integral& rhs) { return *this = *this / rhs; }     bool operator==(const Integral& rhs) const { return val() == rhs.val(); }     bool operator!=(const Integral& rhs) const { return !(*this == rhs); }     const Integral operator-() const { return Integral(-val()); }     const Integral operator++() {       v_ = norm(v_ + 1);       return *this;     }     const Integral operator++(int) {       Integral ret = *this;       ++(*this);       return ret;     }     const Integral operator--() {       v_ = norm(v_ - 1);       return *this;     }     const Integral operator--(int) {       Integral ret = *this;       --(*this);       return ret;     }     Integral power(long long b) const {       long long ret = 1 % MOD, a = v_;       for (; b; b >>= 1, a = a * a % MOD)         if (b & 1) ret = ret * a % MOD;       return ret;     }     Integral inv() const { return power(MOD - 2); }   };   template <int MOD>   std::string to_string(const Integral<MOD>& v) {     return std::string( Integral{v= ) + std::to_string(v.val()) +  } ;   }   template <int MOD, bool kAllowBruteForce = false>   struct Binomial {     std::vector<Integral<MOD>> factor, inv_factor;     explicit Binomial(int n = 0) : factor(n + 1), inv_factor(n + 1) {       factor[0] = 1;       for (int i = 1; i <= n; ++i) factor[i] = factor[i - 1] * i;       inv_factor[n] = factor[n].inv();       for (int i = n; i >= 1; --i) inv_factor[i - 1] = inv_factor[i] * i;     }     ~Binomial() = default;     template <typename T>     Integral<MOD> operator()(T a, T b) const {       if (a < b || b < 0) return 0;       if (a < factor.size()) return factor[a] * inv_factor[b] * inv_factor[a - b];       if constexpr (!kAllowBruteForce) {         throw std::out_of_range( Binomial );       } else {         b = std::min(b, a - b);         Integral<MOD> ret = 1;         for (T i = 1; i <= b; ++i) ret = ret * (a + 1 - i) / i;         return ret;       }     }   };   template <int MOD>   struct PowerTable {     std::vector<Integral<MOD>> arr;     PowerTable(int n, const Integral<MOD>& g) : arr(n + 1) {       arr[0] = 1;       arr[1] = g;       for (int i = 2; i < arr.size(); ++i) arr[i] = arr[i - 1] * arr[1];     }     template <typename T>     Integral<MOD> power(T index) const {       if (0 <= index && index < arr.size()) return arr[index];       return arr[1].power(index);     }   };   const int MOD = 1e9 + 7;   using Mint = Integral<MOD>;   using Binom = Binomial<MOD>;   Binom binom(200);   const int kN = 50 + 5;   const int kM = 2500 + 5;   Mint f[kN][kN][kM];   Mint g[kN][kN][kN][2];   Mint h[kN][kM];   Mint q[kN][kM];   int main() {     std::ios::sync_with_stdio(false);     std::cin.tie(nullptr);     std::istream& reader = std::cin;     int n, T;     reader >> n >> T;     std::vector<std::vector<int>> ts(3);     for (int i = 0; i < n; ++i) {       int t, g;       reader >> t >> g;       ts[g - 1].emplace_back(t);     }     int m[3] = {};     for (int i = 0; i < 3; ++i) m[i] = ts[i].size();     f[0][0][0] = 1;     for (int t : ts[0]) {       for (int i = m[0] - 1; i >= 0; --i)         for (int k = T - t; k >= 0; --k) f[i + 1][0][k + t] += f[i][0][k];     }     for (int t : ts[1]) {       for (int j = m[1] - 1; j >= 0; --j)         for (int i = m[0]; i >= 0; --i)           for (int k = T - t; k >= 0; --k) f[i][j + 1][k + t] += f[i][j][k];     }     g[0][0][0][0] = 1;     for (int i = 0; i <= m[0]; ++i) {       for (int j = 0; j <= m[1]; ++j) {         for (int k = 0; k <= i + j; ++k) {           for (int r = 0; r < 2; ++r)             if (g[i][j][k][r].val()) {               Mint val = g[i][j][k][r].val();               g[i + 1][j][k + 1][0] += val;               g[i][j + 1][k + 1][1] += val;               if (k > 0) {                 if (r == 0) g[i][j + 1][k][1] += val;                 if (r == 1) g[i + 1][j][k][0] += val;               }             }         }       }     }     for (int i = 0; i <= m[0]; ++i) {       for (int j = 0; j <= m[1]; ++j) {         for (int k = 0; k <= i + j; ++k) {           for (int w = 0; w < 2; ++w)             if (g[i][j][k][w].val()) {               for (int r = 0; r <= T; ++r)                 if (f[i][j][r].val()) {                   q[k][r] += f[i][j][r] * g[i][j][k][w] * binom.factor[i] *                              binom.factor[j];                 }             }         }       }     }     h[0][0] = 1;     for (int t : ts[2]) {       for (int j = m[2] - 1; j >= 0; --j)         for (int k = T - t; k >= 0; --k) h[j + 1][k + t] += h[j][k];     }     Mint result = 0;     for (int k = 0; k <= m[0] + m[1]; ++k) {       for (int t = 0; t <= T; ++t)         if (q[k][t].val()) {           1145141919810;           for (int c = std::max(0, k - 1); c <= k + 1 && c <= m[2]; ++c) {             if (!h[c][T - t].val()) continue;             Mint coef = c == k ? 2 : 1;             result += coef * q[k][t] * h[c][T - t] * binom.factor[c];             1145141919810;           }         }     }     printf( %d n , result.val());   }