#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<vector>
#include<array>
#include<string>
#include<stack>
#include<queue>
#include<algorithm>
#include<cassert>
#include<functional>
#include<random>
#include<complex>
#include<bitset>
#include<chrono>
//#include<boost/multiprecision/cpp_int.hpp>
#define int int64_t
#define uint uint64_t
#define REP(i, a, b) for (int64_t i = (int64_t)(a); i < (int64_t)(b); i++)
#define rep(i, a) REP(i, 0, a)
#define SZ(X) ((int64_t)((X).size()))
#define ITR(x, a) for (auto x = a.begin(); x != a.end(); x++)
#define ALL(a) (a.begin()), (a.end())
#define HAS(a, x) (a.find(x) != a.end())
#define Min(x) *min_element(ALL(x))
#define Max(x) *max_element(ALL(x))
#define Unique(L) (L.erase(unique(ALL(L)), L.end()))
#define intmax (std::numeric_limits<int64_t>::max() / 4)
#define doublemax (std::numeric_limits<double>::max() / 4)
using namespace std;
//typedef boost::multiprecision::cpp_int bigint;
const double EPS = 1e-9;
const double PI = acos(-1.0);


class modint {
	//MODが素数であることを前提として実装してあるが、その判定はしていない。
	//あまりが出るような除算をしてはいけない。
private:
	static const int MOD = 1000000007;
public:
	modint() {
		//assert(is_prime(MOD));
		this->number = 0;
	}
	modint(const int src) {
		//assert(is_prime(MOD));
		this->number = opposit(src);
	}
	modint(const modint &src) {
		this->number = src.number;
	}

	modint& operator += (const modint& obj) {
		this->number = san2(this->number + obj.number);
		return *this;
	}
	modint& operator -= (const modint& obj) {
		this->number = san2(this->number - obj.number + MOD);
		return *this;
	}
	modint& operator *= (const modint& obj) {
		this->number = (this->number * obj.number) % MOD;
		return *this;
	}
	modint& operator /= (const modint& obj) {
		this->number = (this->number * inverse(obj.number)) % MOD;
		return *this;
	}
	modint& operator += (const int n) {
		this->number = san2(this->number + opposit(n));
		return *this;
	}
	modint& operator -= (const int n) {
		this->number = san2(this->number - opposit(n) + MOD);
		return *this;
	}
	modint& operator *= (const int n) {
		this->number = (this->number * opposit(n)) % MOD;
		return *this;
	}
	modint& operator /= (const int n) {
		this->number = (this->number * inverse(n)) % MOD;
		return *this;
	}

	modint operator + (const modint obj) { modint re(*this); return re += obj; }
	modint operator - (const modint obj) { modint re(*this); return re -= obj; }
	modint operator * (const modint obj) { modint re(*this); return re *= obj; }
	modint operator / (const modint obj) { modint re(*this); return re /= obj; }
	modint operator + (const int n) { modint re(*this); return re += n; }
	modint operator - (const int n) { modint re(*this); return re -= n; }
	modint operator * (const int n) { modint re(*this); return re *= n; }
	modint operator / (const int n) { modint re(*this); return re /= n; }

	modint operator = (const int n) {
		this->number = opposit(n);
		return *this;
	}
	int get() {
		return number;
	}

private:
	int number;

	int opposit(int n) {
		if (n < 0)n = MOD - ((-n) % MOD);
		return n % MOD;
	}
	int inverse(int n) {
		n = opposit(n);
		int result = 1;
		for (int i = MOD - 2; i; i /= 2) {
			if (i % 2)result = (result * n) % MOD;
			n = (n * n) % MOD;
		}
		return result;
	}
	inline int san2(const int n) {
		return MOD <= n ? n - MOD : n;
	}
	bool is_prime(int n) {
		if (n <= 1)return false;
		if (n == 2)return true;
		if (n % 2 == 0) return false;
		const int upperbound = int(sqrt(n));
		for (int i = 3; i <= upperbound; i += 2) {
			if (n % i == 0) return false;
		}
		return true;
	}
};

struct combi {
private:
	vector<modint>facto_arr;
public:
	combi(const int N) :facto_arr(N) {
		facto_arr[0] = 1;
		REP(i, 1, N)facto_arr[i] = facto_arr[i - 1] * i;
	}
	modint get_combi(const int N, const int C) {
		//combination(N+C,C)を求めて返す。
		if (int(facto_arr.size()) <= N + C) {
			int a = facto_arr.size();
			facto_arr.resize(N + C + 1);
			REP(i, a, N + C + 1)facto_arr[i] = facto_arr[i - 1] * i;
		}
		return facto_arr[N + C] / (facto_arr[N] * facto_arr[C]);
	}
	modint facto(int N) {
		if (int(facto_arr.size()) <= N) {
			int a = facto_arr.size();
			facto_arr.resize(N + 1);
			REP(i, a, N + 1)facto_arr[i] = facto_arr[i - 1] * i;
		}
		return facto_arr[N];
	}
};



signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	int N, X, Y;
	cin >> N >> X >> Y;
	vector<int>c(N), w(N);
	rep(i, N)cin >> c[i] >> w[i];

	int g1 = 0;//最も軽いボールの番号
	REP(i, 1, N)if (w[i] < w[g1]) g1 = i;
	int g2 = -1;//g1と違う色のボールのうち最も軽いものの番号
	rep(i, N)if (c[i] != c[g1])g2 = i;
	if (g2 == -1) {//全てのボールが同じ色なら答えは明らかに1
		cout << 1 << endl;
		return 0;
	}
	rep(i, N)if (c[i] != c[g1] && w[i] < w[g2])g2 = i;

	vector<set<int>>g(N);//交換可能な組に道があるような無向グラフを作る

	//操作1

	vector<array<int,2>>minweight(N + 1);
	rep(i, N + 1)minweight[i][0] = intmax;

	//ボールをiで走査して、各色で最も軽いボールとその重さを記録する
	rep(i, N)if (w[i] < minweight[c[i]][0]) {
		minweight[c[i]][0] = w[i];
		minweight[c[i]][1] = i;
	}

	//ボールをiで走査して、交換可能な組に辺を張る
	rep(i, N)if (minweight[c[i]][1] != i && minweight[c[i]][0] + w[i] <= X) {
		g[i].insert(minweight[c[i]][1]);
		g[minweight[c[i]][1]].insert(i);
	}

	//操作2

	//ボールをiで走査して、交換可能な組に辺を張る
	rep(i, N) {
		if (c[i] == c[g1]) {
			//g2と交換可能か？
			if (w[i] + w[g2] <= Y) {
				g[i].insert(g2);
				g[g2].insert(i);
			}
		}
		else if (c[i] != c[g1]) {
			//g1と交換可能か？
			if (w[i] + w[g1] <= Y) {
				g[i].insert(g1);
				g[g1].insert(i);
			}
		}
	}

	//gをdfsして、答えが何通りか数える
	combi fac(N+1);

	vector<int>searched(N, 0);
	modint ans = 1;
	rep(i, N)if (searched[i] == 0) {
		map<int,int>color;
		int num = 0;
		stack<int>dfs;
		dfs.push(i);
		while (!dfs.empty()) {
			int x = dfs.top(); dfs.pop();
			if (searched[x]++)continue;
			if (color.find(c[x]) == color.end())color[c[x]] = 1;
			else color[c[x]]++;
			num++;
			for (int y : g[x]) {
				dfs.push(y);
			}
		}
		ans *= fac.facto(num);
		auto itr = color.begin();
		while (itr != color.end()) {
			ans /= fac.facto(itr->second);
			itr++;
		}
	}

	cout << ans.get() << endl;

	return 0;
}

Measured memory_bytes: 47872