// 基本テンプレート

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int cross(int xa, int ya, int xb, int yb) {
    return xa*yb - xb*ya;
}

int dot(int xa, int ya, int xb, int yb) {
    return xa*xb + ya*yb;
}

struct Elem {
    int X, P, Q;
    bool operator<(const Elem &e) const {
        return cross(P, Q, e.P, e.Q) < 0;
    }
};

pii get_vec(int x, int y) {
    if(x == 0) return make_pair(0, 1);
    if(y == 0) return make_pair(1, 0);

    // x は必ず正
    if(x < 0) x = -x, y = -y;
    int g = __gcd(x, y>0?y:-y);
    return make_pair(x/g, y/g);
}

signed main() {
    int N, A, B; scanf("%lld%lld%lld", &N, &A, &B);
    vector<Elem> lines;

    int cnt_parallel = 0, par_a = 0, par_b = 0, no_move = 0;
    for(int i=0; i<N; i++) {
        int x, p, q; scanf("%lld%lld%lld", &x, &p, &q);

        // ただの点
        if(p == 0 && q == 0) {
            no_move++;
            continue;
        }

        // 元の？直線と平行
        if(cross(1, A, p, q) == 0) {
            cnt_parallel++;
            int D = dot(1, A, p, q);
            assert(D != 0);
            if(D > 0) par_a++;
            if(D < 0) par_b++;
        }
        else {
            lines.push_back(Elem{x, p, q});
        }
    }

    vector<pii> deg_vec;
    map<pii, int> deg_set;
    for(auto e : lines) {
        pii deg = get_vec(e.P, e.Q);
        deg_vec.push_back(deg);
        deg_set[ deg ]++;
    }

    // printf("no_move = %lld, par_a = %lld, par_b = %lld\n", no_move, par_a, par_b);
    int ans = (par_a * par_b * 2) + (no_move * (par_a + par_b) * 2);
    int M = (int)lines.size();
    for(size_t i=0; i<lines.size(); i++) {
        pii deg = deg_vec[i];
        // printf("par_a = %lld, par_b = %lld, M = %lld, deg = %lld\n", par_a, par_b, M, deg_set[deg]);
        int intersect = par_a + par_b + M - deg_set[deg];
        ans += intersect;
    }
    printf("%lld\n", ans);
    return 0;
}


//
#include<bits/stdc++.h>
const int N = 2e5+10;
const int inf=0x3f3f3f3f;
#define rep(i,n) for(i=0;i<n;i++)
#define mem(a,x) memset(a,x,sizeof(a))
const double PI=acos(-1);
const double eps=1e-9;
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
int ans,t,i,j,k,n,m,b,a;
struct node{
	int vx,vy,x;
}st[N];
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
typedef pair<int,int> PII;
map<PII,int> mp1;
map<int,int> mp2;
set<node>s;
int main(){
	while(scanf("%d%d%d",&n,&a,&b)!=EOF)
	{
		int ans1=0,ans2=0;
		for(int i=0;i<n;i++){
			scanf("%d%d%d",&st[i].x,&st[i].vx,&st[i].vy);
			if(st[i].vy==0&&st[i].vx==0) continue;
			int tmp=a*st[i].vx-st[i].vy;
			mp2[tmp]++;
			ans1+=mp2[tmp]-1;
			int x,y,z;
			x=st[i].vx;
			y=st[i].vy;
			z=gcd(x,y);
			z=abs(z);
			if(z){
				x/=z;
				y/=z;
			}

			mp1[make_pair(x,y)]++;
			ans2+=mp1[make_pair(x,y)]-1;
		}
		printf("%d\n",2*(ans1-ans2));
	}
	return 0;
}
/*
avx-vy
vy=0 vx
	vx/vy
*/


//
#include<bits/stdc++.h>
const int N = 2e5+10;
const int inf=0x3f3f3f3f;
#define rep(i,n) for(i=0;i<n;i++)
#define mem(a,x) memset(a,x,sizeof(a))
const double PI=acos(-1);
const double eps=1e-9;
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll ans,t,i,j,k,n,m,b,a;
struct node{
	ll vx,vy,x;
}st[N];
ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
typedef pair<ll,ll> PII;
map<PII,ll> mp1;
map<ll,ll> mp2;
int main(){
	while(scanf("%lld%lld%lld",&n,&a,&b)!=EOF)
	{
		ll ans1=0,ans2=0;
		for(int i=0;i<n;i++){
			scanf("%lld%lld%lld",&st[i].x,&st[i].vx,&st[i].vy);
			if(st[i].vy==0&&st[i].vx==0) continue;
			ll tmp=a*st[i].vx-st[i].vy;
			mp2[tmp]++;
			ans1+=mp2[tmp]-1;
			ll x,y,z;
			x=st[i].vx;
			y=st[i].vy;
			z=gcd(x,y);
			z=abs(z);
			if(z){
				x/=z;
				y/=z;
			}

			mp1[make_pair(x,y)]++;
			ans2+=mp1[make_pair(x,y)]-1;
		}
		printf("%lld\n",2LL*(ans1-ans2));
	}
	return 0;
}
/*
avx-vy
vy=0 vx
	vx/vy
*/


//
#include<bits/stdc++.h>
const int N = 2e5+10;
const int inf=0x3f3f3f3f;
#define rep(i,n) for(i=0;i<n;i++)
#define mem(a,x) memset(a,x,sizeof(a))
const double PI=acos(-1);
const double eps=1e-9;
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll ans,t,i,j,k,n,m,b,a;
struct node{
	ll vx,vy,x;
}st[N];
ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
typedef pair<ll,ll> PII;
map<PII,ll> mp1;
map<ll,ll> mp2;
int main(){
	while(scanf("%lld%lld%lld",&n,&a,&b)!=EOF)
	{
		int ans1=0,ans2=0;
		for(int i=0;i<n;i++){
			scanf("%lld%lld%lld",&st[i].x,&st[i].vx,&st[i].vy);
			if(st[i].vy==0&&st[i].vx==0) continue;
			ll tmp=a*st[i].vx-st[i].vy;
			mp2[tmp]++;
			ans1+=mp2[tmp]-1;
			ll x,y,z;
			x=st[i].vx;
			y=st[i].vy;
			z=gcd(x,y);
			z=abs(z);
			if(z){
				x/=z;
				y/=z;
			}

			mp1[make_pair(x,y)]++;
			ans2+=mp1[make_pair(x,y)]-1;
		}
		printf("%lld\n",2LL*(ans1-ans2));
	}
	return 0;
}
/*
avx-vy
vy=0 vx
	vx/vy
*/


//
#include<bits/stdc++.h>
const int N = 2e5+10;
const int inf=0x3f3f3f3f;
#define rep(i,n) for(i=0;i<n;i++)
#define mem(a,x) memset(a,x,sizeof(a))
const double PI=acos(-1);
const double eps=1e-9;
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
int ans,t,i,j,k,n,m,b,a;
struct node{
	int vx,vy,x;
}st[N];
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
typedef pair<int,int> PII;
map<PII,int> mp1;
map<int,int> mp2;
set<node>s;
int main(){
	while(scanf("%d%d%d",&n,&a,&b)!=EOF)
	{
		int ans1=0,ans2=0;
		for(int i=0;i<n;i++){
			scanf("%d%d%d",&st[i].x,&st[i].vx,&st[i].vy);
			if(st[i].vy==0) continue;
			int tmp=a*st[i].vx-st[i].vy;
			mp2[tmp]++;
			ans1+=mp2[tmp]-1;
			int x,y,z;
			x=st[i].vx;
			y=st[i].vy;
			z=gcd(x,y);
			z=abs(z);
			x/=z;
			y/=z;

			mp1[make_pair(x,y)]++;
			ans2+=mp1[make_pair(x,y)]-1;
		}
		printf("%d\n",2*(ans1-ans2));
	}
	return 0;
}
/*
avx-vy
vy=0 vx
	vx/vy
*/


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-10;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;

const ld EPS = 1e-18;

int gcd(int a, int b)
{
	if (!b)
		return a;
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<pair<int, int>, pair<int, int>>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		cin >> x.x >> v.x >> v.y;
		x.y = a * x.x + b;
		int d = gcd(v.x, v.y);
		cnt[make_pair(make_pair(v.x / fabs(v.x), v.y / fabs(v.y)), make_pair(v.x / d, v.y / d))]++;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	int ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < n)
	{
		while (r < n && vv[r] - vv[l] < EPS)
			r++;

		ans += (r - l) * (r - l - 1) / 2;
		l = r;
	}

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;

const ld EPS = 1e-10;

int gcd(int a, int b)
{
	if (!b)
		return a;
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<pair<int, int>, pair<int, int>>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		cin >> x.x >> v.x >> v.y;
		x.y = a * x.x + b;
		int d = gcd(v.x, v.y);
		cnt[make_pair(make_pair(v.x / fabs(v.x), v.y / fabs(v.y)), make_pair(v.x / d, v.y / d))]++;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	int ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < n)
	{
		while (r < n && vv[r] - vv[l] < EPS)
			r++;

		ans += (r - l) * (r - l - 1) / 2;
		l = r;
	}

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-11;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-9;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-9;
#1

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-14;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-10;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);
		cnt[make_pair(vx, vy)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < n)
	{
		while (r < n && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-10;

signed main()
{
	ll n, a, b, ans = 0;
	cin >> n >> a >> b;
	map<ll, ll> cnt;
	map<pair<int, int>, ll> parallel;

	map<pair<int, int>, ll> speed;
	ll sp = 0;

	for (int i = 0; i < n; ++i)
	{
		ll x, y, vx, vy;
		cin >> x >> vx >> vy;
		y = a * x + b;

		if (y + vy == a * (x + vx) + b)
		{
			speed[make_pair(vx, vy)]++;
			sp++;
			continue;
		}

		ans += cnt[vy - a * vx] - parallel[make_pair(vx, vy)] - parallel[make_pair(-vx, -vy)];
		parallel[make_pair(vx, vy)]++;
		cnt[vy - a * vx]++;
	}

	ans += sp * (sp - 1) / 2;
	for (auto p : speed)
		ans -= p.second * (p.second - 1) / 2;

	cout << ans * 2;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-10;

signed main()
{
	ll n, a, b, ans = 0;
	cin >> n >> a >> b;
	map<ll, ll> cnt;
	map<pair<int, int>, ll> parallel;

	map<pair<int, int>, ll> speed;
	ll sp = 0;

	for (int i = 0; i < n; ++i)
	{
		ll x, y, vx, vy;
		cin >> x >> vx >> vy;
		y = a * x + b;

		if (y + vy == a * (x + vx) + b)
		{
			speed[make_pair(vx, vy)]++;
			sp++;
			continue;
		}

		ans += cnt[vy - a * vx] - parallel[make_pair(vx, vy)];
		parallel[make_pair(vx, vy)]++;
		cnt[vy - a * vx]++;
	}

	ans += sp * (sp - 1) / 2;
	for (auto p : speed)
		ans -= p.second * (p.second - 1) / 2;

	cout << ans * 2;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;

const ld EPS = 1e-6;

int gcd(int a, int b)
{
	if (!b)
		return a;
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<pair<int, int>, pair<int, int>>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		cin >> x.x >> v.x >> v.y;
		x.y = a * x.x + b;
		int d = gcd(v.x, v.y);
		cnt[make_pair(make_pair(v.x / fabs(v.x), v.y / fabs(v.y)), make_pair(v.x / d, v.y / d))]++;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	int ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < n)
	{
		while (r < n && vv[r] - vv[l] < EPS)
			r++;

		ans += (r - l) * (r - l - 1) / 2;
		l = r;
	}

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-8;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	map<pair<int, int>, int> gg;
	ll gcnt = 0;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (x.y + vy == ld(a) * (x.x + vx) + b)
		{
			gg[make_pair(vx, vy)]++;
			gcnt++;
			continue;
		}

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < vv.size())
	{
		while (r < vv.size() && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	ans += gcnt * (gcnt - 1) / 2;
	for (auto p : gg)
		ans -= (p.second - 1) * p.second / 2;

	cout << 2 * ans;
	return 0;
}


#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <map>

using namespace std;

typedef long double ld;
typedef long long ll;

const ld EPS = 1e-10;

int gcd(int a, int b)
{
	if (!b)
		return max(a, 1);
	else
		return gcd(b, a % b);
}

ld sqr(ld a)
{
	return a * a;
}

struct point
{
	ld x, y;

	point(ld a = 0, ld b = 0) : x(a), y(b) {};

	ld length(point b)
	{
		return sqrt(sqr(x - b.x) + sqr(y - b.y));
	}

	point turning(ld angle)
	{
		point b;
		ld A[2][2] = { { cos(angle), sin(angle) },{ -sin(angle), cos(angle) } };
		b.x = x * A[0][0] + y * A[0][1];
		b.y = x * A[1][0] + y * A[1][1];
		return b;
	}

	point shifting(point a)
	{
		point b;
		b.x = x - a.x;
		b.y = y - a.y;

		return b;
	}
};

int sign(ld v)
{
	if (v < 0)
		return -1;
	else
		return 1;
}

istream &operator >> (istream &in, point &a)
{
	cin >> a.x >> a.y;
	return in;
}

ostream &operator << (ostream &out, point a)
{
	cout << a.x << ' ' << a.y << '\n';
	return out;
}

bool compare(point &a, point &b)
{
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

int det(point a, point b, point c)
{
	point f = b.shifting(a);
	point s = c.shifting(b);
	return f.x * s.y - s.x * f.y;
}

signed main()
{
	int n, a, b;
	cin >> n >> a >> b;
	map<pair<int, int>, int> cnt;

	int x0 = 0, x1 = 1;
	int y0 = a * x0 + b, y1 = a * x1 + b;
	ld angle = atan2(y1 - y0, x1 - x0);
	vector<ld> vv;

	vector<pair<point, point>> challengers;
	for (int i = 0; i < n; ++i)
	{
		point x, v;
		int vx, vy;
		cin >> x.x >> vx >> vy;
		x.y = x.x * ld(a) + ld(b);

		if (vx > 0)
			cnt[make_pair(vx, vy)]++;
		else
			cnt[make_pair(vx * -1, vy * -1)]++;

		v.x = vx, v.y = vy;

		v = v.turning(angle);
		vv.push_back(fabs(v.y));
	}

	long long ans = 0;
	for (auto p : cnt)
		ans -= p.second * (p.second - 1) / 2;

	sort(vv.begin(), vv.end());
	int l = 0, r = 0;
	while (l < n)
	{
		while (r < n && vv[r] - vv[l] < EPS)
			r++;

		ans += ll(r - l) * ll(r - l - 1) / 2LL;
		l = r;
	}

	cout << 2 * ans;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-13){
			while(i < n && eth(v[i].s, v[i -1].s) &&
			     (v[i].s.s != a*v[i].s.f || !v[i].s.s ||
			      v[i].s.f != -v[i -1].s.f))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1 == p2 || p1.f == p2.f && !p1.f
	                || p1.s == p2.s && !p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-7){
			while(i < n && eth(v[i].s, v[i -1].s))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-7){
			while(i < n && v[i].s == v[i -1].s)
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-11){
			while(i < n && eth(v[i].s, v[i -1].s) &&
			     (v[i].s.s != a*v[i].s.f || !v[i].s.s ||
			      v[i].s.f != -v[i -1].s.f))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define ld long double
#define f first
#define s second

bool eth(pair<ll, ll> p1, pair<ll, ll> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<ll, ll> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %lld %lld", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	ll t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-11){
			while(i < n && eth(v[i].s, v[i -1].s) &&
			     (v[i].s.s != a*v[i].s.f || !v[i].s.s ||
			      v[i].s.f != -v[i -1].s.f))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			if(abs(v[i].f -v[i -1].f) < 1e-11) i++;
			ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-11 &&
		   !(eth(v[i -1].s, v[i -2].s) &&
		    (v[i -1].s.s != a*v[i -1].s.f || !v[i -1].s.s ||
		     v[i -1].s.f != -v[i -2].s.f)))
		   //v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-7){
			while(i < n && eth(v[i].s, v[i -1].s) &&
			     (v[i].s.s != a*v[i].s.f || !v[i].s.s ||
			      v[i].s.f != -v[i -1].s.f))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	long long ans = 0, sum = 0, t = 1, ti = 1;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-7){
			while(i < n && v[i].s == v[i -1].s)
				ti++, i++;
			t *= ti;
			if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(sum) ans += sum*(sum +1)*t;
		sum = 0; t = 1;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-7){
			while(i < n && eth(v[i].s, v[i -1].s))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ld long double
#define f first
#define s second

bool eth(pair<int, int> p1, pair<int, int> p2){
	return p1.f*p2.s == p2.f*p1.s;
}

int main(){
	int n, a, b;
	cin >> n >> a >> b;
	pair<ld, pair<int, int> > v[n];

	for(int i = 0; i < n; i++){
		scanf("%*d %d %d", &v[i].s.f, &v[i].s.s);
		v[i].f = (ld)v[i].s.s/a -v[i].s.f;
	}
	sort(v, v +n);

	if(n == 2){
		if(abs(v[0].f -v[1].f) < 1e-7 && v[0].s != v[1].s)
			printf("2\n");
		else printf("0\n");
		return 0;
	}
	int t[n], st = 0, ti = 1;
	long long ans = 0, sum = 0;
	for(int i = 1; i < n; i++){
		while(i < n && abs(v[i].f -v[i -1].f) < 1e-13){
			while(i < n && eth(v[i].s, v[i -1].s) &&
			     (v[i].s.s != 1LL*a*v[i].s.f || !v[i].s.s ||
			      v[i].s.f != -v[i -1].s.f))
				ti++, i++;
			sum += ti;
			t[st++] = ti;
	//	t *= ti;
	//	if(i < n || ti == 1) sum++;
			i++; ti = 1;
		}
		if(i > 2 && i <= n &&
		   abs(v[i -2].f -v[i -1].f) < 1e-7 && v[i -1].s != v[i -2].s)
			sum += t[st++] = 1;
		if(sum) for(int j = 0; j < st; j++)
			ans += t[j]*(sum -t[j]);
		sum = 0; st = 0;
	}

	printf("%lld\n", ans);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
const int N = 200005;
typedef map<LL, LL> mmp;
int main()
{
#ifdef local
    freopen("test.in", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    mmp cnt;
    map<LL,mmp > applese;
    ll n, a, b;
    cin >> n >> a >> b;
    for(int i=1;i<=n;i++)
    {
        ll x, vx, vy;
        cin >> x >> vx >> vy;
        applese[a * vx - vy][vx]++;
        if (cnt.count(a * vx - vy))
            cnt[a * vx - vy]++;
        else
            cnt.insert(make_pair(a * vx - vy, 1));
    }
    ll ans = 0;
    for(auto t: applese)
    {
        ll temp = t.first;
        for(auto pt: t.second)
        {
            ll ins = pt.second * cnt[temp];
            ll dis = pt.second * pt.second;
            ans += ins;
            ans -= dis;
        }
    }
    cout << ans << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e3 + 5;
LL in[100];
LL b[100];
map<pair<LL, LL>,LL> mp;
int main()
{
#ifdef local
    freopen("test.in", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    LL n, a, b;
    cin >> n >> a >> b;
    for (int i = 0; i < n; ++i)
    {
        LL x , q, w;
        cin >> x >> q >> w;
        mp[pair<LL, LL>{q,w}]++;
    }
    LL ans = n * n;
    for (auto it: mp)
        ans -= (it.second * it.second);
    cout << ans << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long long ll;
const int N = 200005;
LL in[100];
LL b[100];
map<pair<LL, LL>,LL> mp;
ll a[N];
int main()
{
#ifdef local
    freopen("test.in", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    LL n, a, b;
    cin >> n >> a >> b;
    //cerr << __gcd(2, -4) << endl;
    for (int i = 0; i < n; ++i)
    {
        LL x,q,w;
        cin >> x >> q >> w;
        ll qq = abs(q);
        LL now = __gcd(abs(q),abs(w));
        if (a * q == w)
            mp[{q, w}]++;
        else
            mp[{q / now, w / now}]++;
    }
    LL ans = n * n;
    for (auto it: mp)
    {
        //cerr << it.first.first << ' ' << it.first.second << ' ' << it.second << endl;
        ans -= (it.second * it.second);
    }
    cout << ans << endl;

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e3 + 5;
LL in[100];
LL b[100];
map<pair<LL, LL>,LL> mp;
int main()
{
#ifdef local
    freopen("test.in", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    LL n, a, b;
    cin >> n >> a >> b;
    a = abs(a);
    b = abs(b);
    LL gcd = __gcd(a, b);
    for (int i = 0; i < n; ++i)
    {
        LL x,q,w;
        cin >> x >> q >> w;
        q = abs(q);
        w = abs(w);
        LL now = __gcd(q, w);
        if (q * gcd == now * a)
            mp[{q,w}]++;
        else
            mp[{q / now, w / now}]++;
    }
    LL ans = n * n;
    for (auto it: mp)
        ans -= (it.second * it.second);
    cout << ans << endl;
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ldb;
typedef pair<ll,ll> pll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
template <typename T> using ordered_set =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define CLEAR(a) memset(a,0,sizeof(a))
#define all(x) x.begin(),x.end()
#define sz(x) ((int)x.size())
#define loop(i,a,b) for(ll i=a;i<=b;i++)
#define rloop(i,a,b) for(ll i=b;i>=a;i--)
#define ios_tie() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define trace1(x)                cout <<#x<<":"<<x<< endl;
#define trace2(x, y)             cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<< endl;
#define trace3(x, y, z)          cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<<" | "<<#z<<":"<<z<<endl;
#define trace4(a, b, c, d)       cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<<" | "<<#c<<":"<<c<<" | "<<#d<<":"<<d<<endl;

const ll INF = 0x3f3f3f3f;
const ll mod = 1e9+7;
const ll maxn = 1e5+1;
const ldb PI = acos(-1);

ll POWER[65];
ll power(ll x,ll y) {ll res=1; x%=mod; while(y) {if(y&1) res=(res*x)%mod; y>>=1; x=(x*x)%mod; }return res;}
ll inv(ll x) {return power(x,mod-2);}
void precompute() {POWER[0]=1; for(int i=1;i<63;i++) POWER[i]=POWER[i-1]<<1LL; }

int main()
{
    ios_tie();
    ll n,a,b;
    cin>>n>>a>>b;
    ll x[n],vx[n],vy[n],y[n];
    loop(i,0,n-1)
    {
        cin>>x[i]>>vx[i]>>vy[i];
        y[i]=a*x[i]+b;
    }
    pair<ldb,ldb> ghost[n];
    loop(i,0,n-1)
    {
        if(vx[i]!=0)
        {
            ghost[i].ff=1.0*vy[i]/vx[i];
            ghost[i].ss=1.0*y[i]-1.0*ghost[i].ff*x[i];
        }
        else
        {
            ghost[i].ff=1.0*INF;
            ghost[i].ss=1.0*INF;
        }
    }
    ll ex[n] = {0};
    loop(i,0,n-1)
    {
        loop(j,i+1,n-1)
        {
            if(ghost[i].ff==1.0*INF && ghost[j].ff==1.0*INF)
            {
                if(x[i]==x[j])          //same path
                {
                    if(vy[i]!=vy[j])
                    {
                        ex[i]++;
                        ex[j]++;
                    }
                }
                continue;
            }
            if(ghost[i].ff==ghost[j].ff)
            {
                if(ghost[i].ss==ghost[j].ss)        // same path
                {
                    if(!(vx[i]==vx[j] && vy[i]==vy[j]))
                    {
                        ex[i]++;
                        ex[j]++;
                        //trace2(i+1,j+1);
                    }
                }
            }
            else
            {
                ex[i]++;
                ex[j]++;
                //trace2(i+1,j+1);
            }
        }
    }
    ll ans = 0;
    loop(i,0,n-1)
        ans+=ex[i];
    cout<<ans;
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ldb;
typedef pair<ll,ll> pll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
template <typename T> using ordered_set =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define CLEAR(a) memset(a,0,sizeof(a))
#define all(x) x.begin(),x.end()
#define sz(x) ((ll)x.size())
#define loop(i,a,b) for(ll i=a;i<=b;i++)
#define rloop(i,a,b) for(ll i=b;i>=a;i--)
#define ios_tie() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define trace1(x)                cout <<#x<<":"<<x<< endl;
#define trace2(x, y)             cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<< endl;
#define trace3(x, y, z)          cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<<" | "<<#z<<":"<<z<<endl;
#define trace4(a, b, c, d)       cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<<" | "<<#c<<":"<<c<<" | "<<#d<<":"<<d<<endl;

const ll INF = 0x3f3f3f3f;
const ll mod = 1e9+7;
const ll maxn = 1e5+1;
const ldb PI = acos(-1);

ll POWER[65];
ll power(ll x,ll y) {ll res=1; x%=mod; while(y) {if(y&1) res=(res*x)%mod; y>>=1; x=(x*x)%mod; }return res;}
ll inv(ll x) {return power(x,mod-2);}
void precompute() {POWER[0]=1; for(int i=1;i<63;i++) POWER[i]=POWER[i-1]<<1LL; }

int main()
{
    ios_tie();
    ll n,a,b;
    cin>>n>>a>>b;
    map<ll,ll> intersect;
    map<pll,ll> same;
    ll ans = 0;
    loop(i,0,n-1)
    {
        ll x,vx,vy;
        cin>>x>>vx>>vy;
        ans += intersect[a*vx-vy] - same[{vx,vy}];
        intersect[a*vx-vy]++;
        same[{vx,vy}]++;
    }
    cout<<2*ans;
    return 0;
}


#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ldb;
typedef pair<ll,ll> pll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
template <typename T> using ordered_set =  tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define CLEAR(a) memset(a,0,sizeof(a))
#define all(x) x.begin(),x.end()
#define sz(x) ((int)x.size())
#define loop(i,a,b) for(ll i=a;i<=b;i++)
#define rloop(i,a,b) for(ll i=b;i>=a;i--)
#define ios_tie() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
#define trace1(x)                cout <<#x<<":"<<x<< endl;
#define trace2(x, y)             cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<< endl;
#define trace3(x, y, z)          cout <<#x<<":"<<x<<" | "<<#y<<":"<<y<<" | "<<#z<<":"<<z<<endl;
#define trace4(a, b, c, d)       cout <<#a<<":"<<a<<" | "<<#b<<":"<<b<<" | "<<#c<<":"<<c<<" | "<<#d<<":"<<d<<endl;

const ll INF = 0x3f3f3f3f;
const ll mod = 1e9+7;
const ll maxn = 1e5+1;
const ldb PI = acos(-1);

ll POWER[65];
ll power(ll x,ll y) {ll res=1; x%=mod; while(y) {if(y&1) res=(res*x)%mod; y>>=1; x=(x*x)%mod; }return res;}
ll inv(ll x) {return power(x,mod-2);}
void precompute() {POWER[0]=1; for(int i=1;i<63;i++) POWER[i]=POWER[i-1]<<1LL; }

int main()
{
    ios_tie();
    ll n,a,b;
    cin>>n>>a>>b;
    ll x[n],vx[n],vy[n],y[n];
    loop(i,0,n-1)
    {
        cin>>x[i]>>vx[i]>>vy[i];
        y[i]=a*x[i]+b;
    }
    pair<ldb,ldb> ghost[n];
    loop(i,0,n-1)
    {
        if(vx[i]!=0)
        {
            ghost[i].ff=1.0*vy[i]/vx[i];
            ghost[i].ss=1.0*y[i]-1.0*ghost[i].ff*x[i];
        }
        else
        {
            ghost[i].ff=1.0*mod;
            ghost[i].ss=1.0*INF;
        }
    }
    ll ex[n] = {0};
    loop(i,0,n-1)
    {
        loop(j,i+1,n-1)
        {
            if(ghost[i].ff==1.0*mod && ghost[j].ff==1.0*mod)
            {
                if(x[i]==x[j])          //same path
                {
                    //if(vy[i]!=vy[j])
                    {
                        ex[i]++;
                        ex[j]++;
                    }
                }
                continue;
            }
            if(ghost[i].ff==ghost[j].ff)
            {
                if(ghost[i].ss==ghost[j].ss)        // same path
                {
                    if(!(vx[i]==vx[j] && vy[i]==vy[j]))
                    {
                        ex[i]++;
                        ex[j]++;
                        //trace2(i+1,j+1);
                    }
                }
            }
            else
            {
                ex[i]++;
                ex[j]++;
                //trace2(i+1,j+1);
            }
        }
    }
    ll ans = 0;
    loop(i,0,n-1)
        ans+=ex[i];
    cout<<ans;
    return 0;
}


#include <iostream>
#include <map>
#define DIM 200005
using namespace std;
int n,a,b;
map<long long,long long> collide;
map<pair<int,int>,int> parallel;
long long rez;
int main()
{
    //freopen("date.in","r",stdin);
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++)
    {
          int x,vx,vy;
          cin>>x>>vx>>vy;
          rez += collide[a*vx-vy] - parallel[make_pair(vx,vy)];
          collide[a*vx-vy]++;
          parallel[make_pair(vx,vy)]++;
    }
    cout<<2*rez;
    return 0;
}


#include <iostream>
#include <map>
#define DIM 200005
using namespace std;
int n,a,b;
map<int,int> collide;
map<pair<int,int>,int> parallel;
long long rez;
int main()
{
    //freopen("date.in","r",stdin);
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++)
    {
          int x,vx,vy;
          cin>>x>>vx>>vy;
          rez += collide[a*vx-vy] - parallel[make_pair(vx,vy)];
          collide[a*vx-vy]++;
          parallel[make_pair(vx,vy)]++;
    }
    cout<<2*rez;
    return 0;
}


#include <iostream>
#include <map>
#define DIM 200005
using namespace std;
int n;
long long a,b;
map<long long,long long> collide;
map<pair<int,int>,int> parallel;
long long rez;
int main()
{
    //freopen("date.in","r",stdin);
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++)
    {
          int x,vx,vy;
          cin>>x>>vx>>vy;
          rez += collide[a*vx-vy] - parallel[make_pair(vx,vy)];
          collide[a*vx-vy]++;
          parallel[make_pair(vx,vy)]++;
    }
    cout<<2*rez;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

// 965 D - dont delete submit first

typedef long long ll;
#define rep(i, start, end) for(int i = start; i < end; ++i)
#define per(i, start, end) for(int i = (int)start-1; i >= end; --i)
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define all(x) x.begin(), x.end()

int main()
{
    ios_base::sync_with_stdio(false);
//    freopen("input.txt", "r", stdin);
    int n, a, b;
    cin >> n >> a >> b;
    map<ll, int> cnt;
    map<pair<int, int>, int> par;
    ll ans = 0;
    rep(i, 0, n)
    {
        ll x, Vx, Vy;
        cin >> x >> Vx >> Vy;
        ans += cnt[1LL * a * Vx - Vy] - par[mp(Vx,Vy)];
        cnt[a*Vx - Vy]++;
        par[mp(Vx,Vy)]++;
    }
    cout << 2*ans << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

// 965 D - dont delete submit first

typedef long long ll;
#define rep(i, start, end) for(int i = start; i < end; ++i)
#define per(i, start, end) for(int i = (int)start-1; i >= end; --i)
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define all(x) x.begin(), x.end()

int main()
{
    ios_base::sync_with_stdio(false);
//    freopen("input.txt", "r", stdin);
    ll n, a, b;
    cin >> n >> a >> b;
    map<ll, int> cnt;
    map<pair<ll, ll>, int> par;
    ll ans = 0;
    rep(i, 0, n)
    {
        ll x, Vx, Vy;
        cin >> x >> Vx >> Vy;
        ans += cnt[a * Vx - Vy] - par[mp(Vx,Vy)];
        cnt[a*Vx - Vy]++;
        par[mp(Vx,Vy)]++;
    }
    cout << 2*ans << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

// 965 D - dont delete submit first

typedef long long ll;
#define rep(i, start, end) for(int i = start; i < end; ++i)
#define per(i, start, end) for(int i = (int)start-1; i >= end; --i)
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define all(x) x.begin(), x.end()

int main()
{
    ios_base::sync_with_stdio(false);
//    freopen("input.txt", "r", stdin);
    ll n, a, b;
    cin >> n >> a >> b;
    map<ll, int> cnt;
    map<pair<int, int>, int> par;
    ll ans = 0;
    rep(i, 0, n)
    {
        ll x, Vx, Vy;
        cin >> x >> Vx >> Vy;
        ans += cnt[a * Vx - Vy] - par[mp(Vx,Vy)];
        cnt[a*Vx - Vy]++;
        par[mp(Vx,Vy)]++;
    }
    cout << 2*ans << endl;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5 + 10;
long long sqr(long long x)
{
	return x * x;
}
const double eps = 1e-4 , pi = acos(-1.0);

inline int cmp(double x)
{
    return (x > eps) - (x < -eps);
}
map<pair<long,long>,int> haha;
int N,a,b;
int n,m;
long long ans = 0;
struct Point
{
	long long x,y,v;
	bool operator < (const Point& R) const {
        return v < R.v;
    }
	long long operator % (const Point& R) const {
        return x * R.x + y * R.y;
	}
	long long operator * (const Point& R) const {
		return x * R.y - y * R.x;
	}
	bool operator == (const Point& R) const {
		return x == R.x && y == R.y;
	}
	double len()
	{
		return sqrt(sqr(x) + sqr(y));
	}
}p[maxn],on[maxn],o;

int main()
{
//	freopen("1.in","r",stdin);
	cin >> N >> a >> b;
	o.x = 1;
	o.y = a;
	int X;
	Point tmp;
	for(int i = 0; i < N; i++)
	{
		scanf("%d%lld%lld",&X,&tmp.x,&tmp.y);
		if(tmp * o == 0)
			on[++m] = tmp, on[m].v = 0;
		else
		{
			p[++n] = tmp;
			p[n].v = p[n] * o;
		}
	}
	sort(on+1,on+1+m);
	sort(p+1,p+1+n);
	ans = 1ll * m * (m - 1);
	for(int i = 1; i <= m; i++)
	{
		int j = i;
		while(j < m && on[j+1] == on[i])
			j++;
		ans -= 1ll * (j - i) * (j - i + 1);
		i = j;
	}
	for(int i = 1; i <= n; i++)
	{
		int j = i;
		while(j < n && p[j+1].v == p[i].v)
			j++;
		sort(p+i,p+j+1);
		ans += 1ll * (j - i + 1) * (j - i);
		for(int ii = i; ii <= j; ii++)
		{
			int jj = ii;
			while(jj < j && p[jj+1] == p[ii])
				jj++;
			ans -= 1ll * (jj - ii) * (jj - ii + 1);
			ii = jj;
		}
		i = j;
	}
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int maxn = 2e5 + 10;
long long sqr(long long x)
{
	return x * x;
}
const double eps = 1e-10 , pi = acos(-1.0);

inline int cmp(double x)
{
    return (x > eps) - (x < -eps);
}

int N,a,b;
int n,m;
long long ans = 0;
struct Point
{
	long long x,y,p;
	double v,a;
	bool operator < (const Point& R) const {
		if(cmp(v - R.v) == 0)
			return x < R.x;
        return v < R.v;
    }
	long long operator % (const Point& R) const {
        return x * R.x + y * R.y;
	}
	double len()
	{
		return sqrt(sqr(x) + sqr(y));
	}
}p[maxn],o;

double sinAngle(Point A , Point B) {
	double tmp;
	if((A % B) >= 0)
		tmp = 1;
	else
		tmp = -1;
    return sin(acos((A % B) / A.len() / B.len()));
}

int main()
{
	cin >> N >> a >> b;
	o.x = 1;
	o.y = a;
	int X,VX,VY;
	for(int i = 0; i < N; i++)
	{
		scanf("%d%d%d",&X,&VX,&VY);
		if(VX == 0 && VY == 0)
			m++;
		else
		{
			n++;
			p[n].p = X;
			p[n].x = VX;
			p[n].y = VY;
			p[n].a = sinAngle(p[n],o);
			p[n].v = p[n].len() * p[n].a;
		}
	}
	sort(p+1,p+1+n);
	for(int i = 1; i <= n; i++)
	{
		if(1ll * p[i].x * a == 1ll  * p[i].y)
			ans += m;
	}
	for(int i = 1; i <= n; i++)
	{
		int j = i;
		while(cmp(p[j+1].v - p[i].v) == 0 && j + 1 <= n)
			j++;
		if(cmp(p[i].v) ==0)
		{
			for(int ii = i; ii <= j; ii++)
				{
					int jj = ii;
					while(p[jj+1].x == p[ii].x && jj+1 <= j)
						jj++;
					ans += (jj-ii+1) * (j-i-jj+ii);
					ii = jj;
				}
		}
		else
			ans += 1ll * (j - i + 1) * (j - i);
		i = j;
	}
	cout << ans << endl;
	return 0;
}


#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

ll modInv(ll a, ll b = MOD - 2) {
	if (b & 1) return a * modInv(a, b ^ 1) % MOD;
	if (b == 0) return 1;
	return modInv(a*a % MOD, b >> 1);
}

// res[k] = \sum_{i,j : i^j == k} a[i] b[j]
// overflows if n res[i] overflows
void xorTF(vector<ll>& v) {
	for (int b = 1; b < v.size(); b *= 2) {
		for (int i = 0; i < v.size(); ++i) {
			if (i & b) continue;
			ll ri = v[i^b];
			v[i^b] = (MOD + v[i] - ri) % MOD;
			v[i] = (v[i] + ri) % MOD;
		}
	}
}
vector<ll> xorConv(vector<ll> a, vector<ll> b) {
	xorTF(a); xorTF(b);
	for (int i = 0; i < a.size(); ++i) a[i] = a[i]*b[i] % MOD;
	xorTF(a);
	ll ti = modInv(a.size());
	for (ll& v : a) v = (v * ti) % MOD;
	return a;
}

const int N = 1e5;
const int K = 1e5;
const int H = 17; // 2^17 > 1e5
vector<pair<int, int>> conns[N];
vector<ll> cycles[K];
int visited[N];

pair<int, int> dfs(int i, int p, int& cc) {
	visited[i] = visited[p] + 1;
	pair<int, int> res = {-1, -1};
	for (auto pr : conns[i]) {
		int t = pr.first;
		if (t == p) continue;
		if (visited[t]) {
			if (visited[t] < visited[i]) {
				res = {t, cc};
				cycles[cc].resize(1<<H, 0);
				cycles[cc][0] = 1;
				++cycles[cc][pr.second];
				++cc;
			}
		} else {
			auto sub = dfs(t, i, cc);
			if (sub.first != -1) {
				res = sub;
				++cycles[res.second][pr.second];
			}
		}
	}
	if (res.first == i) res = {-1, -1};
	return res;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

	int xr = 0;
	for (int i = 0; i < m; ++i) {
		int a, b, w;
		cin >> a >> b >> w;
		--a; --b;
		conns[a].push_back({b, w});
		conns[b].push_back({a, w});
		xr ^= w;
	}

	int cc = 0; // <= 42
	dfs(0, 0, cc);

	vector<ll> res(1<<H, 0);
	res[0] = 1;
	vector<ll> can = res;

	for (int i = 0; i < cc; ++i) {
		res = xorConv(res, cycles[i]);
		can = xorConv(can, cycles[i]);
		for (ll& v : can) v = min(v, 1ll);
	}
	for (int j = 0; j < H; ++j) {
		if (can[j ^ xr]) {
			cout << j << ' ' << res[j ^ xr] << '\n';
			break;
		}
	}
}


#include <iostream>
#include <vector>
#include <valarray>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

ll modInv(ll a, ll b = MOD - 2) {
	if (b & 1) return a * modInv(a, b ^ 1) % MOD;
	if (b == 0) return 1;
	return modInv(a*a % MOD, b >> 1);
}

// res[k] = \sum_{i,j : i^j == k} a[i] b[j]
// overflows if n res[i] overflows
valarray<ll> xorTF(valarray<ll> v) {
	for (int b = 1; b < v.size(); b *= 2) {
		for (int i = 0; i < v.size(); ++i) {
			if (i & b) continue;
			ll ri = v[i^b];
			v[i^b] = (MOD + v[i] - ri) % MOD;
			v[i] = (v[i] + ri) % MOD;
		}
	}
	return v;
}
vector<ll> xorConv(const vector<ll>& a, const vector<ll>& b, int h) {
	valarray<ll> res = xorTF((xorTF({a.data(), 1ull<<h}) * xorTF({b.data(), 1ull<<h})) % MOD) * modInv(1<<h) % MOD;
	return vector<ll>(begin(res), end(res));
}

const int N = 1e5;
const int K = 50;
const int H = 17;
vector<pair<int, int>> conns[N];
vector<ll> cycles[K];
int visited[N];

pair<int, int> dfs(int i, int p, int& cc) {
	visited[i] = visited[p] + 1;
	pair<int, int> res = {-1, -1};
	for (auto pr : conns[i]) {
		int t = pr.first;
		if (t == p) continue;
		if (visited[t]) {
			if (visited[t] < visited[i]) {
				res = {t, cc};
				cycles[cc].resize(1<<H, 0);
				++cycles[cc][pr.second];
				++cc;
			}
		} else {
			auto sub = dfs(t, i, cc);
			if (sub.first != -1) {
				res = sub;
				++cycles[res.second][pr.second];
			}
		}
	}
	if (res.first == i) res = {-1, -1};
	return res;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

	int xr = 0;
	for (int i = 0; i < m; ++i) {
		int a, b, w;
		cin >> a >> b >> w;
		--a; --b;
		conns[a].push_back({b, w});
		conns[b].push_back({a, w});
		xr ^= w;
	}

	int cc = 0; // <= 42
	dfs(0, 0, cc);

	vector<ll> res(1<<H, 0);
	res[0] = 1;
	vector<ll> can = res;

	for (int i = 0; i < cc; ++i) {
		res = xorConv(res, cycles[i], H);
		can = xorConv(can, cycles[i], H);
		for (auto& v : can) v = min(v, 1ll);
	}
	for (int j = 0; j < H; ++j) {
		if (can[j ^ xr]) {
			cout << j << ' ' << res[j ^ xr] << '\n';
			break;
		}
	}
}


#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

ll modInv(ll a, ll b = MOD - 2) {
	if (b & 1) return a * modInv(a, b ^ 1) % MOD;
	if (b == 0) return 1;
	return modInv(a*a % MOD, b >> 1);
}

// res[k] = \sum_{i,j : i^j == k} a[i] b[j]
// overflows if n res[i] overflows
void xorTF(vector<ll>& v) {
	for (int b = 1; b < v.size(); b *= 2) {
		for (int i = 0; i < v.size(); ++i) {
			if (i & b) continue;
			ll ri = v[i^b];
			v[i^b] = (MOD + v[i] - ri) % MOD;
			v[i] = (v[i] + ri) % MOD;
		}
	}
}
vector<ll> xorConv(vector<ll> a, vector<ll> b) {
	xorTF(a); xorTF(b);
	for (int i = 0; i < a.size(); ++i) a[i] = a[i]*b[i] % MOD;
	xorTF(a);
	ll ti = modInv(a.size());
	for (ll& v : a) v = (v * ti) % MOD;
	return a;
}

const int N = 10 + (int)1e5;
const int K = 100;
const int H = 17; // 2^17 > 1e5
vector<pair<int, int>> conns[N];
vector<ll> cycles[K];
int visited[N];

pair<int, int> dfs(int i, int p, int& cc) {
	visited[i] = visited[p] + 1;
	pair<int, int> res = {-1, -1};
	for (auto pr : conns[i]) {
		int t = pr.first;
		if (t == p) continue;
		if (visited[t]) {
			if (visited[t] < visited[i]) {
				res = {t, cc};
				cycles[cc].resize(1<<H, 0);
				// cycles[cc][0] = 1; // do we need to have a spanning tree?
				++cycles[cc][pr.second];
				++cc;
			}
		} else {
			auto sub = dfs(t, i, cc);
			if (sub.first != -1) {
				res = sub;
				++cycles[res.second][pr.second];
			}
		}
	}
	if (res.first == i) res = {-1, -1};
	return res;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

	int xr = 0;
	for (int i = 0; i < m; ++i) {
		int a, b, w;
		cin >> a >> b >> w;
		--a; --b;
		conns[a].push_back({b, w});
		conns[b].push_back({a, w});
		xr ^= w;
	}

	int cc = 0; // <= 42
	dfs(0, 0, cc);

	vector<ll> res(1<<H, 0);
	res[0] = 1;
	vector<ll> can = res;

	for (int i = 0; i < cc; ++i) {
		res = xorConv(res, cycles[i]);
		can = xorConv(can, cycles[i]);
		for (ll& v : can) v = min(v, 1ll);
	}
	for (int j = 0; j < (1<<H); ++j) {
		if (can[j ^ xr]) {
			ll cou = res[j ^ xr];
			cou = (cou % MOD + MOD) % MOD;
			cout << j << ' ' << cou << '\n';
			break;
		}
	}
}


#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

const int N = 1e5;
const int K = 50;
const int H = 17; // 2^17 > 1e5
vector<pair<int, int>> conns[N];
vector<int> cycles[K];
int visited[N];

ll modInv(ll a, ll b = MOD - 2) {
	if (b & 1) return a * modInv(a, b ^ 1) % MOD;
	if (b == 0) return 1;
	return modInv(a*a % MOD, b >> 1);
}
int TI = modInv(1<<H);

// res[k] = \sum_{i,j : i^j == k} a[i] b[j]
// overflows if n res[i] overflows
void xorTF(vector<int>& v) {
	for (int b = 1; b < v.size(); b *= 2) {
		for (int i = 0; i < v.size(); ++i) {
			if (i & b) continue;
			int ri = v[i^b];
			v[i^b] = v[i] - ri;
			v[i] = v[i] + ri;
			if (v[i^b] < 0) v[i^b] += MOD;
			if (v[i] >= MOD) v[i] -= MOD;
		}
	}
}
vector<int> xorConv(vector<int> a, vector<int> b) {
	xorTF(a); xorTF(b);
	for (int i = 0; i < a.size(); ++i) a[i] = (ll)a[i]*b[i] % MOD;
	xorTF(a);
	for (int& v : a) v = (ll)v * TI % MOD;
	return a;
}

pair<int, int> dfs(int i, int p, int& cc) {
	visited[i] = visited[p] + 1;
	pair<int, int> res = {-1, -1};
	for (auto pr : conns[i]) {
		int t = pr.first;
		if (t == p) continue;
		if (visited[t]) {
			if (visited[t] < visited[i]) {
				res = {t, cc};
				cycles[cc].resize(1<<H, 0);
				// cycles[cc][0] = 1; // do we need to have a spanning tree?
				++cycles[cc][pr.second];
				++cc;
			}
		} else {
			auto sub = dfs(t, i, cc);
			if (sub.first != -1) {
				res = sub;
				++cycles[res.second][pr.second];
			}
		}
	}
	if (res.first == i) res = {-1, -1};
	return res;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

	int xr = 0;
	for (int i = 0; i < m; ++i) {
		int a, b, w;
		cin >> a >> b >> w;
		--a; --b;
		conns[a].push_back({b, w});
		conns[b].push_back({a, w});
		xr ^= w;
	}

	int cc = 0; // <= 42
	dfs(0, 0, cc);

	vector<int> res(1<<H, 0);
	res[0] = 1;
	vector<int> can = res;

	for (int i = 0; i < cc; ++i) {
		res = xorConv(res, cycles[i]);
		can = xorConv(can, cycles[i]);
		for (int& v : can) v = min(v, 1);
	}
	for (int j = 0; j < (1<<H); ++j) {
		if (can[j ^ xr]) {
			cout << j << ' ' << res[j ^ xr] << '\n';
			break;
		}
	}
}


#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

ll modInv(ll a, ll b = MOD - 2) {
	if (b & 1) return a * modInv(a, b ^ 1) % MOD;
	if (b == 0) return 1;
	return modInv(a*a % MOD, b >> 1);
}

// res[k] = \sum_{i,j : i^j == k} a[i] b[j]
// overflows if n res[i] overflows
void xorTF(vector<ll>& v) {
	for (int b = 1; b < v.size(); b *= 2) {
		for (int i = 0; i < v.size(); ++i) {
			if (i & b) continue;
			ll ri = v[i^b];
			v[i^b] = (MOD + v[i] - ri) % MOD;
			v[i] = (v[i] + ri) % MOD;
		}
	}
}
vector<ll> xorConv(vector<ll> a, vector<ll> b) {
	xorTF(a); xorTF(b);
	for (int i = 0; i < a.size(); ++i) a[i] = a[i]*b[i] % MOD;
	xorTF(a);
	ll ti = modInv(a.size());
	for (ll& v : a) v = (v * ti) % MOD;
	return a;
}

const int N = 10 + (int)1e5;
const int K = 100;
const int H = 17; // 2^17 > 1e5
vector<pair<int, int>> conns[N];
vector<ll> cycles[K];
int visited[N];

pair<int, int> dfs(int i, int p, int& cc) {
	visited[i] = visited[p] + 1;
	pair<int, int> res = {-1, -1};
	for (auto pr : conns[i]) {
		int t = pr.first;
		if (t == p) continue;
		if (visited[t]) {
			if (visited[t] < visited[i]) {
				res = {t, cc};
				cycles[cc].resize(1<<H, 0);
				// cycles[cc][0] = 1; // do we need to have a spanning tree?
				++cycles[cc][pr.second];
				++cc;
			}
		} else {
			auto sub = dfs(t, i, cc);
			if (sub.first != -1) {
				res = sub;
				++cycles[res.second][pr.second];
			}
		}
	}
	if (res.first == i) res = {-1, -1};
	return res;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

	int xr = 0;
	for (int i = 0; i < m; ++i) {
		int a, b, w;
		cin >> a >> b >> w;
		--a; --b;
		conns[a].push_back({b, w});
		conns[b].push_back({a, w});
		xr ^= w;
	}

	int cc = 0; // <= 42
	dfs(0, 0, cc);

	vector<ll> res(1<<H, 0);
	res[0] = 1;
	vector<ll> can = res;

	for (int i = 0; i < cc; ++i) {
		res = xorConv(res, cycles[i]);
		can = xorConv(can, cycles[i]);
		for (ll& v : can) v = min(v, 1ll);
	}
	for (int j = 0; j < H; ++j) {
		if (can[j ^ xr]) {
			ll cou = res[j ^ xr];
			cou = (cou % MOD + MOD) % MOD;
			cout << j << ' ' << cou << '\n';
			break;
		}
	}
}


#pragma GCC optimize("Ofast", "unroll-loops")

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctime>
#include <cassert>
#include <unordered_map>
#include <fstream>
#include <random>
#include <cstring>
#include <bitset>
#include <functional>
#include <tuple>
#include <complex>
#include <chrono>
#include <climits>

using namespace std;

#define all(a) (a).begin(), (a).end()
#define sz(a) (int)(a).size()

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using ull = unsigned long long;
using Complex = complex<double>;

mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
default_random_engine generator;
// mt19937 rnd(1);

const int MAXN = 100100;
const int P = 1e9 + 7;

void mul(int &a, int b) {
    a = (ll)a * b % P;
}

void add(int &a, int b) {
    a += b;
    if (a >= P) {
        a -= P;
    }
}

void sub(int &a, int b) {
    a -= b;
    if (a < 0) {
        a += P;
    }
}

int binPow(int a, int b) {
    int res = 1;
    int x = a;
    for (; b > 0; b >>= 1) {
        if (b & 1) {
            mul(res, x);
        }
        mul(x, x);
    }
    return res;
}

vector<int> xorConvolution(vector<int> cur) {
    int n = sz(cur);
    vector<int> ncur(n);
    for (int len = 1; len < n; len <<= 1) {
        for (int pos = 0; pos < n; pos += len) {
            for (int i = 0; i < len; ++pos, ++i) {
                ncur[pos] = cur[pos];
                add(ncur[pos], cur[pos + len]);

                ncur[pos + len] = cur[pos];
                sub(ncur[pos + len], cur[pos + len]);
            }
        }
        cur.swap(ncur);
    }
    return cur;
}

vector<int> xorProduct(vector<int> a, vector<int> b) {
    int n = 1;
    for (; n < max(sz(a), sz(b)); n <<= 1);
    a.resize(n);
    b.resize(n);
    a = xorConvolution(a);
    b = xorConvolution(b);
    int rn = binPow(n, P - 2);
    for (int i = 0; i < n; ++i) {
        mul(a[i], b[i]);
        mul(a[i], rn);
    }
    return xorConvolution(a);
}

vector<int> g[MAXN];
vector<int> w[MAXN];

vector<int> path;
vector<int> ed;

int x = 0;
vector<vector<int>> block;
int tin[MAXN];
int used[MAXN];

int tim = 0;

int dfs(int v, int p = -1) {
    used[v] = 1;
    tin[v] = tim++;
    path.push_back(v);

    int up = tin[v];

    for (int i = 0; i < sz(g[v]); ++i) {
        int u = g[v][i];
        if (u == p) {
            continue;
        }
        if (used[u] && tin[u] < tin[v]) {
            up = min(up, tin[u]);
            block.push_back({w[v][i]});

            for (int i = sz(path) - 1; path[i] != u; --i) {
                block.back().push_back(ed[i - 1]);
            }
        }
        if (!used[u]) {
            ed.push_back(w[v][i]);
            int fup = dfs(u, v);
            up = min(up, fup);
            if (fup > tin[v]) {
                // cout << "here " << v <<  " " << w[v][i] << endl;
                x ^= w[v][i];
            }
            ed.pop_back();
        }
    }
    path.pop_back();

    // cout << v << " " << up << endl;

    return up;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int u, v, ww;
        cin >> u >> v >> ww;
        --u; --v;
        g[u].push_back(v);
        g[v].push_back(u);
        w[u].push_back(ww);
        w[v].push_back(ww);
    }

    dfs(0);

    if (sz(block) == 0) {
        cout << x << " " << 1 << endl;
        return 0;
    }

    for (auto &vct : block) {
        int y = 0;
        for (int el : vct) {
            y ^= el;
        }
        for (int &el : vct) {
            el ^= y;
        }
        // vct.push_back(y);
    }
    // for (int i = 0; i < sz(block); ++i) {
    //     for (int el : block[i]) {
    //         cout << el << " ";
    //     }
    //     cout << endl;
    // }

    for (int &el : block[0]) {
        el ^= x;
    }

    int k = sz(block);
    vector<vector<int>> poly(k, vector<int>(1 << 17));
    vector<vector<int>> poly_cut(k, vector<int>(1 << 17));

    for (int i = 0; i < k; ++i) {
        for (int el : block[i]) {
            ++poly[i][el];
            poly_cut[i][el] |= 1;
        }
    }

    for (int i = 1; i < k; ++i) {
        poly[0] = xorProduct(poly[0], poly[i]);
        poly_cut[0] = xorProduct(poly_cut[0], poly_cut[i]);
        for (int j = 0; j < (1 << 17); ++j) {
            poly_cut[i][j] = (poly_cut[i][j] > 0);
        }
    }

    for (int i = 0; i < (1 << 17); ++i) {
        if (poly_cut[0][i] != 0) {
            cout << i << " " << poly[0][i] << endl;
            return 0;
        }
    }

#ifdef LOCAL
    cerr << "Time: " << double(clock()) / CLOCKS_PER_SEC << endl;
#endif
}


#pragma GCC optimize("Ofast", "unroll-loops")

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctime>
#include <cassert>
#include <unordered_map>
#include <fstream>
#include <random>
#include <cstring>
#include <bitset>
#include <functional>
#include <tuple>
#include <complex>
#include <chrono>
#include <climits>

using namespace std;

#define all(a) (a).begin(), (a).end()
#define sz(a) (int)(a).size()

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using ull = unsigned long long;
using Complex = complex<double>;

mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
default_random_engine generator;
// mt19937 rnd(1);

const int MAXN = 100100;
const int P = 1e9 + 7;

void mul(int &a, int b) {
    a = (ll)a * b % P;
}

void add(int &a, int b) {
    a += b;
    if (a >= b) {
        a -= P;
    }
}

void sub(int &a, int b) {
    a -= b;
    if (a < 0) {
        a += P;
    }
}

int binPow(int a, int b) {
    int res = 1;
    int x = a;
    for (; b > 0; b >>= 1) {
        if (b & 1) {
            mul(res, x);
        }
        mul(x, x);
    }
    return res;
}

vector<int> xorConvolution(vector<int> cur) {
    int n = sz(cur);
    vector<int> ncur(n);
    for (int len = 1; len < n; len <<= 1) {
        for (int pos = 0; pos < n; pos += len) {
            for (int i = 0; i < len; ++pos, ++i) {
                ncur[pos] = cur[pos];
                add(ncur[pos], cur[pos + len]);

                ncur[pos + len] = cur[pos];
                sub(ncur[pos + len], cur[pos + len]);
            }
        }
        cur.swap(ncur);
    }
    return cur;
}

vector<int> xorProduct(vector<int> a, vector<int> b) {
    int n = 1;
    for (; n < max(sz(a), sz(b)); n <<= 1);
    a.resize(n);
    b.resize(n);
    a = xorConvolution(a);
    b = xorConvolution(b);
    int rn = binPow(n, P - 2);
    for (int i = 0; i < n; ++i) {
        mul(a[i], b[i]);
        mul(a[i], rn);
    }
    return xorConvolution(a);
}

vector<int> g[MAXN];
vector<int> w[MAXN];

vector<int> path;
vector<int> ed;

int x = 0;
vector<vector<int>> block;
int tin[MAXN];
int used[MAXN];

int tim = 0;

int dfs(int v, int p = -1) {
    used[v] = 1;
    tin[v] = tim++;
    path.push_back(v);

    int up = tin[v];

    for (int i = 0; i < sz(g[v]); ++i) {
        int u = g[v][i];
        if (u == p) {
            continue;
        }
        if (used[u] && tin[u] < tin[v]) {
            up = min(up, tin[u]);
            block.push_back({w[v][i]});

            for (int i = sz(path) - 1; path[i] != u; --i) {
                block.back().push_back(ed[i - 1]);
            }
        }
        if (!used[u]) {
            ed.push_back(w[v][i]);
            int fup = dfs(u, v);
            up = min(up, fup);
            if (fup > tin[v]) {
                // cout << "here " << v <<  " " << w[v][i] << endl;
                x ^= w[v][i];
            }
            ed.pop_back();
        }
    }
    path.pop_back();

    // cout << v << " " << up << endl;

    return up;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int u, v, ww;
        cin >> u >> v >> ww;
        --u; --v;
        g[u].push_back(v);
        g[v].push_back(u);
        w[u].push_back(ww);
        w[v].push_back(ww);
    }

    dfs(0);

    if (sz(block) == 0) {
        cout << x << " " << 1 << endl;
        return 0;
    }

    // for (int i = 0; i < sz(block); ++i) {
    //     for (int el : block[i]) {
    //         cout << el << " ";
    //     }
    //     cout << endl;
    // }

    for (auto &vct : block) {
        int y = 0;
        for (int el : vct) {
            y ^= el;
        }
        for (int &el : vct) {
            el ^= y;
        }
        vct.push_back(y);
    }

    // cout << x << endl;

    for (int &el : block[0]) {
        el ^= x;
    }

    int k = sz(block);
    vector<vector<int>> poly(k, vector<int>(1 << 17));
    vector<vector<int>> poly_cut(k, vector<int>(1 << 17));

    for (int i = 0; i < k; ++i) {
        for (int el : block[i]) {
            ++poly[i][el];
            poly_cut[i][el] |= 1;
        }
    }

    for (int i = 1; i < k; ++i) {
        poly[0] = xorProduct(poly[0], poly[i]);
        poly_cut[0] = xorProduct(poly_cut[0], poly_cut[i]);
        for (int j = 0; j < (1 << 17); ++j) {
            poly_cut[i][j] = (poly_cut[i][j] > 0);
        }
    }

    for (int i = 0; i < (1 << 17); ++i) {
        if (poly_cut[0][i] != 0) {
            cout << i << " " << poly[0][i] << endl;
            return 0;
        }
    }

#ifdef LOCAL
    cerr << "Time: " << double(clock()) / CLOCKS_PER_SEC << endl;
#endif
}


#pragma GCC optimize("Ofast", "unroll-loops")

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctime>
#include <cassert>
#include <unordered_map>
#include <fstream>
#include <random>
#include <cstring>
#include <bitset>
#include <functional>
#include <tuple>
#include <complex>
#include <chrono>
#include <climits>

using namespace std;

#define all(a) (a).begin(), (a).end()
#define sz(a) (int)(a).size()

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using ull = unsigned long long;
using Complex = complex<double>;

mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
default_random_engine generator;
// mt19937 rnd(1);

const int MAXN = 100100;
const int P = 1e9 + 7;

void mul(int &a, int b) {
    a = (ll)a * b % P;
}

void add(int &a, int b) {
    a += b;
    if (a >= P) {
        a -= P;
    }
}

void sub(int &a, int b) {
    a -= b;
    if (a < 0) {
        a += P;
    }
}

int binPow(int a, int b) {
    int res = 1;
    int x = a;
    for (; b > 0; b >>= 1) {
        if (b & 1) {
            mul(res, x);
        }
        mul(x, x);
    }
    return res;
}

vector<int> xorConvolution(vector<int> cur) {
    int n = sz(cur);
    vector<int> ncur(n);
    for (int len = 1; len < n; len <<= 1) {
        for (int pos = 0; pos < n; pos += len) {
            for (int i = 0; i < len; ++pos, ++i) {
                ncur[pos] = cur[pos];
                add(ncur[pos], cur[pos + len]);

                ncur[pos + len] = cur[pos];
                sub(ncur[pos + len], cur[pos + len]);
            }
        }
        cur.swap(ncur);
    }
    return cur;
}

vector<int> xorProduct(vector<int> a, vector<int> b) {
    int n = 1;
    for (; n < max(sz(a), sz(b)); n <<= 1);
    a.resize(n);
    b.resize(n);
    a = xorConvolution(a);
    b = xorConvolution(b);
    int rn = binPow(n, P - 2);
    for (int i = 0; i < n; ++i) {
        mul(a[i], b[i]);
        mul(a[i], rn);
    }
    return xorConvolution(a);
}

vector<int> g[MAXN];
vector<int> w[MAXN];

vector<int> path;
vector<int> ed;

int x = 0;
vector<vector<int>> block;
int tin[MAXN];
int used[MAXN];

int tim = 0;

int dfs(int v, int p = -1) {
    used[v] = 1;
    tin[v] = tim++;
    path.push_back(v);

    int up = tin[v];

    for (int i = 0; i < sz(g[v]); ++i) {
        int u = g[v][i];
        if (u == p) {
            continue;
        }
        if (used[u] && tin[u] < tin[v]) {
            up = min(up, tin[u]);
            block.push_back({w[v][i]});

            for (int i = sz(path) - 1; path[i] != u; --i) {
                block.back().push_back(ed[i - 1]);
            }
        }
        if (!used[u]) {
            ed.push_back(w[v][i]);
            int fup = dfs(u, v);
            up = min(up, fup);
            if (fup > tin[v]) {
                // cout << "here " << v <<  " " << w[v][i] << endl;
                x ^= w[v][i];
            }
            ed.pop_back();
        }
    }
    path.pop_back();

    // cout << v << " " << up << endl;

    return up;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int u, v, ww;
        cin >> u >> v >> ww;
        --u; --v;
        g[u].push_back(v);
        g[v].push_back(u);
        w[u].push_back(ww);
        w[v].push_back(ww);
    }

    dfs(0);

    if (sz(block) == 0) {
        cout << x << " " << 1 << endl;
        return 0;
    }

    for (auto &vct : block) {
        int y = 0;
        for (int el : vct) {
            y ^= el;
        }
        for (int &el : vct) {
            el ^= y;
        }
        vct.push_back(y);
    }
    // for (int i = 0; i < sz(block); ++i) {
    //     for (int el : block[i]) {
    //         cout << el << " ";
    //     }
    //     cout << endl;
    // }

    for (int &el : block[0]) {
        el ^= x;
    }

    int k = sz(block);
    vector<vector<int>> poly(k, vector<int>(1 << 17));
    vector<vector<int>> poly_cut(k, vector<int>(1 << 17));

    for (int i = 0; i < k; ++i) {
        for (int el : block[i]) {
            ++poly[i][el];
            poly_cut[i][el] |= 1;
        }
    }

    for (int i = 1; i < k; ++i) {
        poly[0] = xorProduct(poly[0], poly[i]);
        poly_cut[0] = xorProduct(poly_cut[0], poly_cut[i]);
        for (int j = 0; j < (1 << 17); ++j) {
            poly_cut[i][j] = (poly_cut[i][j] > 0);
        }
    }

    for (int i = 0; i < (1 << 17); ++i) {
        if (poly_cut[0][i] != 0) {
            cout << i << " " << poly[0][i] << endl;
            return 0;
        }
    }

#ifdef LOCAL
    cerr << "Time: " << double(clock()) / CLOCKS_PER_SEC << endl;
#endif
}


#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;

const int N = 100000 + 42;
const int V = 1 << 17;
const ll mod7 = 1000000007;
vector<pair<int, int>> g[N];
int used[N];

ll powi(ll a, ll b, ll m) {
    ll c = 1;
    while (b) {
        if (b & 1)
            c = (c*a) % m;
        a = (a*a) % m;
        b >>= 1;
    }
    return c;
}

void fwht(vector<ll> & a) {
    for (int j = 1; j < a.size(); j <<= 1) {
        for (int i = 0; i < a.size(); i++) {
            if (i & j) {
                int u = a[i - j];
                int v = a[i];
                a[i - j] = u + v;
                a[i] = u - v;
                if (a[i - j] >= mod7) a[i - j] -= mod7;
                if (a[i] < 0) a[i] += mod7;
            }
        }
    }
}

int par[N];
int www[N];

vector<vector<int>> cycles;

void dfs(int v, int p = -1, int ww = 0) {
    www[v] = ww;
    used[v] = true;
    par[v] = p;
    for (pair<int, int> e : g[v]) {
        int to = e.first; int w = e.second;
        if (to == p) continue;
        if (!used[to]) {
            dfs(to, v, w);
        } else {
            if (used[to] == 2) continue;
            int ptr = v;
            vector<int> cycle = { w };
            while (ptr != to) {
                used[ptr] = 2;
                cycle.push_back(www[ptr]);
                ptr = par[ptr];
            }
            used[ptr] = 2;
            cycles.emplace_back(move(cycle));
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    int n, m; cin >> n >> m;
    int allxor = 0;
    for (int i = 0; i < m; i++) {
        int a, b, w; cin >> a >> b >> w; a--; b--;
        g[a].push_back({ b,w });
        g[b].push_back({ a,w });
        allxor ^= w;
    }
    dfs(0);
    vector<ll> v(V);
    vector<ll> vv(V);
    v[allxor] = 1;
    fwht(v);
    fwht(vv);
    for (auto cycle : cycles) {
        vector<ll> u(V);
        vector<ll> uu(V);
        for (int c : cycle) u[c]++;
        for (int c : cycle) uu[c]=1;
        fwht(u);
        fwht(uu);
        for (int i = 0; i < V; i++) v[i] = v[i] * u[i] % mod7;
        for (int i = 0; i < V; i++) vv[i] = vv[i] && uu[i];
    }
    fwht(v);
    fwht(vv);

    ll inv = powi(V, mod7 - 2, mod7);
    for (int i = 0; i < V; i++) v[i] = v[i] * inv % mod7;
    for (int i = 0; i < V; i++) {
        if (vv[i]) {
            cout << i << " " << v[i] << endl;
            break;
        }
    }
    return 0;
}


#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;

const int N = 100000 + 42;
const int V = 1 << 17;
const ll mod7 = 1000000007;
vector<pair<int, int>> g[N];
int used[N];

ll powi(ll a, ll b, ll m) {
    ll c = 1;
    while (b) {
        if (b & 1)
            c = (c*a) % m;
        a = (a*a) % m;
        b >>= 1;
    }
    return c;
}

void fwht(vector<ll> & a, bool mod = true) {
    for (int j = 1; j < a.size(); j <<= 1) {
        for (int i = 0; i < a.size(); i++) {
            if (i & j) {
                int u = a[i - j];
                int v = a[i];
                a[i - j] = u + v;
                a[i] = u - v;
                if (a[i - j] >= mod7 && mod) a[i - j] -= mod7;
                if (a[i] < 0 && mod) a[i] += mod7;
            }
        }
    }
}

int par[N];
int www[N];

vector<vector<int>> cycles;

void dfs(int v, int p = -1, int ww = 0) {
    www[v] = ww;
    used[v] = true;
    par[v] = p;
    for (pair<int, int> e : g[v]) {
        int to = e.first; int w = e.second;
        if (to == p) continue;
        if (!used[to]) {
            dfs(to, v, w);
        } else {
            if (used[to] == 2) continue;
            int ptr = v;
            vector<int> cycle = { w };
            while (ptr != to) {
                used[ptr] = 2;
                cycle.push_back(www[ptr]);
                ptr = par[ptr];
            }
            used[ptr] = 2;
            cycles.emplace_back(move(cycle));
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    int n, m; cin >> n >> m;
    int allxor = 0;
    for (int i = 0; i < m; i++) {
        int a, b, w; cin >> a >> b >> w; a--; b--;
        g[a].push_back({ b,w });
        g[b].push_back({ a,w });
        allxor ^= w;
    }
    dfs(0);
    vector<ll> v(V);
    vector<ll> vv(V);
    v[allxor] = 1;
    vv[allxor] = 1;
    fwht(v);
    fwht(vv, false);
    for (auto cycle : cycles) {
        vector<ll> u(V);
        vector<ll> uu(V);
        for (int c : cycle) u[c]++;
        for (int c : cycle) uu[c]=1;
        fwht(u);
        fwht(uu, false);
        for (int i = 0; i < V; i++) v[i] = v[i] * u[i] % mod7;
        for (int i = 0; i < V; i++) vv[i] = vv[i] * uu[i];
        fwht(vv, false);
        for (int i = 0; i < V; i++) vv[i] = !!vv[i];
        fwht(vv, false);
    }
    fwht(v);
    fwht(vv, false);

    ll inv = powi(V, mod7 - 2, mod7);
    for (int i = 0; i < V; i++) v[i] = v[i] * inv % mod7;
    for (int i = 0; i < V; i++) {
        if (vv[i]) {
            cout << i << " " << v[i] << endl;
            break;
        }
    }
    return 0;
}


#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;

const int N = 100000 + 42;
const int V = 1 << 17;
const ll mod7 = 1000000007;
vector<pair<int, int>> g[N];
int used[N];

ll powi(ll a, ll b, ll m) {
    ll c = 1;
    while (b) {
        if (b & 1)
            c = (c*a) % m;
        a = (a*a) % m;
        b >>= 1;
    }
    return c;
}

void fwht(vector<ll> & a) {
    for (int j = 1; j < a.size(); j <<= 1) {
        for (int i = 0; i < a.size(); i++) {
            if (i & j) {
                int u = a[i - j];
                int v = a[i];
                a[i - j] = u + v;
                a[i] = u - v;
                if (a[i - j] >= mod7) a[i - j] -= mod7;
                if (a[i] < 0) a[i] += mod7;
            }
        }
    }
}

int par[N];
int www[N];

vector<vector<int>> cycles;

void dfs(int v, int p = -1, int ww = 0) {
    www[v] = ww;
    used[v] = true;
    par[v] = p;
    for (pair<int, int> e : g[v]) {
        int to = e.first; int w = e.second;
        if (to == p) continue;
        if (!used[to]) {
            dfs(to, v, w);
        } else {
            if (used[to] == 2) continue;
            int ptr = v;
            vector<int> cycle = { w };
            while (ptr != to) {
                used[ptr] = 2;
                cycle.push_back(www[ptr]);
                ptr = par[ptr];
            }
            used[ptr] = 2;
            cycles.emplace_back(move(cycle));
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    int n, m; cin >> n >> m;
    int allxor = 0;
    for (int i = 0; i < m; i++) {
        int a, b, w; cin >> a >> b >> w; a--; b--;
        g[a].push_back({ b,w });
        g[b].push_back({ a,w });
        allxor ^= w;
    }
    dfs(0);
    vector<ll> v(V);
    v[allxor] = 1;
    fwht(v);
    for (auto cycle : cycles) {
        vector<ll> u(V);
        for (int c : cycle) u[c]++;
        fwht(u);
        for (int i = 0; i < V; i++) v[i] = v[i] * u[i] % mod7;
    }
    fwht(v);

    ll inv = powi(V, mod7 - 2, mod7);
    for (int i = 0; i < V; i++) v[i] = v[i] * inv % mod7;
    for (int i = 0; i < V; i++) {
        if (v[i]) {
            cout << i << " " << v[i] << endl;
            break;
        }
    }
    return 0;
}


#include <bits/stdc++.h>

#define itn int
#define all(x) (x).begin(), (x).end()
#define make_unique(x) sort(all((x))); (x).resize(unique(all((x))) - (x).begin())

#define random_shuffle(...) shuffle(__VA_ARGS__, rng)
#define rand() rng()

using namespace std;

inline int nxt() {
	int x;
	scanf("%d", &x);
	return x;
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int L = 17;
const int N = 1 << L;

long long a[N];
long long b[N];

void wh(long long* b, long long* e) {
	if (e == b + 1) {
		return;
	}
	long long *m = b + (e - b) / 2;
	wh(b, m);
	wh(m, e);
	while (m != e) {
		*b += *m;
		*m = *b - 2 * (*m);
		++b, ++m;
	}
}

vector<pair<int, int>> g[N];
vector<int> huili;
vector<char> used;
vector<pair<int, int>> order;

void dfs(int v, int p) {
	used[v] = 1;
	for (const auto& [to, id] : g[v]) {
		if (id == p) {
			continue;
		}
		if (used[to] == 1) {
			continue;
		} else if (used[to]) {
			huili.push_back(id);
		} else {
			dfs(to, id);
		}
	}
	if (p > -1) {
		order.push_back({v, p});
	}
	used[v] = 2;
}

int main() {
	int n = nxt(), m = nxt();
	vector<int> w(m);
	for (int i = 0; i < m; ++i) {
		itn u = nxt() - 1, v = nxt() - 1;
		w[i] = nxt();
		g[u].push_back({v, i});
		g[v].push_back({u, i});
	}

	used.assign(n, 0);

	dfs(0, -1);
	vector<long long> shit(m);
	for (int x : huili) {
		shit[x] = rand() % 1000000000;
		shit[x] <<= 31;
		shit[x] |= (long long)rand() % 1000000000;
	}
	for (const auto& [v, id] : order) {
		for (const auto& [to, idx] : g[v]) {
			assert(to > -1);
			if (id == idx) {
				continue;
			}
			shit[id] ^= shit[idx];
		}
	}

	vector<char> bridges(m);
	int off = 0;
	for (int i = 0; i < m; ++i) {
		bridges[i] = (shit[i] == 0);
		off ^= w[i];
	}

	used.assign(n, 0);
	a[off] = 1;

	const int mod = 1000000007;
	int d2 = 1;
	for (int i = 0; i < L; ++i) {
		if (d2 % 2) {
			d2 += mod;
		}
		d2 /= 2;
	}
	for (int i = 0; i < n; ++i) {
		if (used[i]) {
			continue;
		}
		vector<int> st = {i};
		used[i] = 1;
		int cn = 0;
		while (!st.empty()) {
			++cn;
			int v = st.back();
			st.pop_back();
			for (const auto& [to, id] : g[v]) {
				if (bridges[id]) {
					continue;
				}
				b[w[id]] += 1;
				if (!used[to]) {
					used[to] = 1;
					st.push_back(to);
				}
			}
		}
		if (cn == 1) {
			continue;
		}
		for (int i = 0; i < N; ++i) {
			b[i] /= 2;
		}
		wh(a, a + N);
		wh(b, b + N);
		for (int i = 0; i < N; ++i) {
			a[i] *= b[i];
			a[i] %= mod;
		}
		wh(a, a + N);
		for (int i = 0; i < N; ++i) {
			a[i] = a[i] % mod * d2 % mod;
		}
		memset(b, 0, sizeof(b));
	}

	int idx = 0;
	while (a[idx] == 0) {
		++idx;
	}
	cout << idx << " " << a[idx] << "\n";

	return 0;
}


#include <bits/stdc++.h>

#define itn int
#define all(x) (x).begin(), (x).end()
#define make_unique(x) sort(all((x))); (x).resize(unique(all((x))) - (x).begin())

#define random_shuffle(...) shuffle(__VA_ARGS__, rng)
#define rand() rng()

using namespace std;

inline int nxt() {
	int x;
	scanf("%d", &x);
	return x;
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int L = 17;
const int N = 1 << L;

long long a[N];
long long aa[N];
long long b[N];
long long bb[N];

void wh(long long* b, long long* e) {
	if (e == b + 1) {
		return;
	}
	long long *m = b + (e - b) / 2;
	wh(b, m);
	wh(m, e);
	while (m != e) {
		*b += *m;
		*m = *b - 2 * (*m);
		++b, ++m;
	}
}

vector<pair<int, int>> g[N];
vector<int> huili;
vector<char> used;
vector<pair<int, int>> order;

void dfs(int v, int p) {
	used[v] = 1;
	for (const auto& [to, id] : g[v]) {
		if (id == p) {
			continue;
		}
		if (used[to] == 1) {
			continue;
		} else if (used[to]) {
			huili.push_back(id);
		} else {
			dfs(to, id);
		}
	}
	if (p > -1) {
		order.push_back({v, p});
	}
	used[v] = 2;
}

int main() {
	int n = nxt(), m = nxt();
	vector<int> w(m);
	for (int i = 0; i < m; ++i) {
		itn u = nxt() - 1, v = nxt() - 1;
		w[i] = nxt();
		g[u].push_back({v, i});
		g[v].push_back({u, i});
	}

	used.assign(n, 0);

	dfs(0, -1);
	vector<long long> shit(m);
	for (int x : huili) {
		shit[x] = rand() % 1000000000;
		shit[x] <<= 31;
		shit[x] |= (long long)rand() % 1000000000;
	}
	for (const auto& [v, id] : order) {
		for (const auto& [to, idx] : g[v]) {
			assert(to > -1);
			if (id == idx) {
				continue;
			}
			shit[id] ^= shit[idx];
		}
	}

	vector<char> bridges(m);
	int off = 0;
	for (int i = 0; i < m; ++i) {
		bridges[i] = (shit[i] == 0);
		off ^= w[i];
	}

	used.assign(n, 0);
	a[off] = 1;
	aa[off] = 1;

	const int mod = 1000000007;
	int d2 = 1;
	for (int i = 0; i < L; ++i) {
		if (d2 % 2) {
			d2 += mod;
		}
		d2 /= 2;
	}
	for (int i = 0; i < n; ++i) {
		if (used[i]) {
			continue;
		}
		vector<int> st = {i};
		used[i] = 1;
		int cn = 0;
		while (!st.empty()) {
			++cn;
			int v = st.back();
			st.pop_back();
			for (const auto& [to, id] : g[v]) {
				if (bridges[id]) {
					continue;
				}
				b[w[id]] += 1;
				if (!used[to]) {
					used[to] = 1;
					st.push_back(to);
				}
			}
		}
		if (cn == 1) {
			continue;
		}
		for (int i = 0; i < N; ++i) {
			b[i] /= 2;
			bb[i] = b[i];
		}
		wh(a, a + N);
		wh(b, b + N);
		wh(aa, aa + N);
		wh(bb, bb + N);
		for (int i = 0; i < N; ++i) {
			a[i] %= mod;
			b[i] %= mod;
			if (a[i] < 0) {
				a[i] += mod;
			}
			if (b[i] < 0) {
				b[i] += mod;
			}
			a[i] *= b[i];
			a[i] %= mod;
			aa[i] *= bb[i];
		}
		wh(a, a + N);
		wh(aa, aa + N);
		for (int i = 0; i < N; ++i) {
			a[i] = a[i] % mod * d2 % mod;
			if (a[i] < 0) {
				a[i] += mod;
			}
		}
		memset(b, 0, sizeof(b));
	}

	int idx = 0;
	while (a[idx] == 0 && aa[idx] == 0) {
		++idx;
	}
	cout << idx << " " << a[idx] << "\n";

	return 0;
}