Problem:
Problem F: Directional Resemblance

Vectors have their directions and two vectors make an angle between them. Given a set of three-dimensional vectors, your task is to find the pair among them that makes the smallest angle.

Input

The input is a sequence of datasets. A dataset specifies a set of three-dimensional vectors, some of which are directly given in the dataset and the others are generated by the procedure described below.

Each dataset is formatted as follows.

m n S W
x1 y1 z1
x2 y2 z2
:
xm ym zm

The first line contains four integers m, n, S, and W.

The integer m is the number of vectors whose three components are directly specified in the
dataset. Starting from the second line, m lines have the three components of m vectors. The i-th line of which indicates the vector vi = (xi, yi, zi). All the vector components are positive integers less than or equal to 100.

The integer n is the number of vectors generated by the following procedure.

int g = S;
for(int i=m+1; i<=m+n; i++) {
x[i] = (g/7) %100 + 1;
y[i] = (g/700) %100 + 1;
z[i] = (g/70000)%100 + 1;
if( g%2 == 0 ) { g = (g/2); }
else { g = (g/2) ^ W; }
}

For i = m + 1, . . . , m + n, the i-th vector vi of the set has three components x[i], y[i], and z[i] generated by this procedure.

Here, values of S and W are the parameters S and W given in the first line of the dataset. You may assume 1 ≤ S ≤ 109 and 1 ≤ W ≤ 109.

The total number of vectors satisfies 2 ≤ m + n ≤ 12 × 104. Note that exactly the same vector may be specified twice or more in a single dataset.

A line containing four zeros indicates the end of the input. The total of m+n for all the datasets in the input never exceeds 16 × 105.

Output

For each dataset, output the pair of vectors among the specified set with the smallest non-zero angle in between. It is assured that there are at least two vectors having different directions.

Vectors should be indicated by their three components. The output for a pair of vectors va and vb should be formatted in a line as follows.

xa ya za xb yb zb

Two vectors (xa, ya, za) and (xb, yb, zb) are ordered in the dictionary order, that is, va < vb if xa < xb, or if xa = xb and ya < yb, or if xa = xb, ya = yb and za < zb. When a vector pair is output, the smaller vector in this order should be output first.

If more than one pair makes the equal smallest angle, the pair that is the smallest among them in the dictionary order between vector pairs should be output. The pair (vi, vj) is smaller than the pair (vk, vl) if vi < vk, or if vi = vk and vj < vl.

Sample Input

4 0 2013 1124
1 1 1
2 2 2
2 1 1
1 2 1
2 100 131832453 129800231
42 40 46
42 40 46
0 100000 7004674 484521438
0 0 0 0

Output for the Sample Input

1 1 1 1 2 1
42 40 46 83 79 91
92 92 79 99 99 85

Solution in C++14 (judge verdict: Memory Limit Exceeded)

#include "bits/stdc++.h"
using namespace std;
using ld = long double;
const ld eps = 1e-15;

ld getdis(vector<ld>&l, vector<ld>&r) {
	ld sum = 0;
	for (int i = 0; i < 3; ++i) {
		sum += (l[i] - r[i])*(l[i] - r[i]);
	}
	return sqrt(sum);
}

struct po {
	int index;
	vector<ld> coors;
	po(int _d) :coors(_d) {
		index = -1;
	}
	po(int _index, vector<ld>_coors) :index(_index), coors(_coors) {

	}
	po() {}
};
ld getdis(po&lpo, po&rpo) {
	return getdis(lpo.coors, rpo.coors);
}
template<class T>
class axisSorter {
	int k;
public:
	axisSorter(int _k) : k(_k) {}
	bool operator()(const T &a, const T &b) {
		return a.coors[k] < b.coors[k];
	}
};



struct Ans {
	ld dis;
	pair<int, int>p;

};


bool operator<(const Ans&l, const Ans&r) {
	if (abs(l.dis - r.dis) < eps) {
		assert(l.p.first < l.p.second);
		assert(r.p.first < r.p.second);
		return l.p < r.p;
	}
	else {
		return l.dis < r.dis;
	}
	return true;
}
Ans answer;

template<class T, int Dim = 3>
struct kdtree {
public:
	T midpo;
	vector<T>pos;
	kdtree<T> *ltree, *rtree;
	int depth;
	int axis;
	kdtree(const T &p_) :midpo(p_), ltree(nullptr), rtree(nullptr) {

	}
	~kdtree() {
		if (ltree != nullptr) {
			delete(ltree);
			ltree = nullptr;
		}

		if (rtree != nullptr) {
			delete(rtree);
			rtree = nullptr;
		}
	}

	kdtree(vector<T>&ps_, const int& l, const int& r, const int depth_ = 0) : ltree(nullptr), rtree(nullptr), depth(depth_), axis(depth%Dim) {
		init(ps_, l, r);
	}
	/*vector<T>query(const T & amin, const T&amax) {
	vector<T>ans;
	bool aok = true;
	for (int i = 0; i < Dim; ++i) {
	if (amin.coors[i] <= midpo.coors[i] && midpo.coors[i] <= amax.coors[i]) {

	}
	else {
	aok = false;
	break;
	}
	}
	if (aok) {
	ans.emplace_back(val);
	}
	axisSorter<T> as(axis);
	if (as(midpo, amax) || midpo.coors[axis] == amax.coors[axis]) {
	if (rtree != nullptr) {
	vector<T>tans(rtree->query(amin, amax));
	ans.insert(ans.end(), tans.begin(), tans.end());
	}
	}
	if (as(amin, midpo) || midpo.coors[axis] == amin.coors[axis]) {
	if (ltree != nullptr) {
	vector<T>tans(ltree->query(amin, amax));
	ans.insert(ans.end(), tans.begin(), tans.end());
	}
	}
	return ans;
	}*/
	void getmindis() {
		/*if (ltree != nullptr) {
		auto p =ltree->getmindis();
		if (ansnum > p.second) {
		ansnum = p.second;
		ansp = p.first;
		}
		}
		if (rtree != nullptr) {
		auto p =  rtree->getmindis();
		if (ansnum > p.second) {
		ansnum = p.second;
		ansp = p.first;
		}
		}*/

		vector<po>lpos, rpos;
		ld axisvalue = midpo.coors[axis];

		if (ltree != nullptr) {
			for (auto &po : ltree->pos) {
				if (axisvalue>po.coors[axis] - eps * 1000000 && po.coors[axis]>axisvalue - sqrt(answer.dis) - eps * 1000000) {
					lpos.emplace_back(po);
				}
			}
		}
		if (rtree != nullptr) {
			for (auto &po : rtree->pos) {
				if (axisvalue<po.coors[axis] + eps * 1000000 && po.coors[axis]<axisvalue + sqrt(answer.dis) + eps * 1000000) {
					rpos.emplace_back(po);
				}
			}
		}

		for (auto& lpo : lpos) {
			for (auto& rpo : rpos) {
				ld dis = getdis(lpo, rpo);
				pair<int, int> p(rpo.index, lpo.index);
				if (p.first > p.second)swap(p.first, p.second);
				Ans nans{ dis,p };
				answer = min(answer, nans);
			}
			{
				ld dis = getdis(lpo, midpo);
				pair<int, int> p(midpo.index, lpo.index);
				if (p.first > p.second)swap(p.first, p.second);
				Ans nans{ dis,p };
				answer = min(answer, nans);
			}
		}
		for (auto& rpo : rpos) {
			ld dis = getdis(midpo, rpo);
			pair<int, int> p(midpo.index, rpo.index);
			if (p.first > p.second)swap(p.first, p.second);
			Ans nans{ dis,p };
			if (p.first == 1524 && 2763 == p.second) {
				int a = 1; a++;
			}
			//if (p.first == 2763 && 1524 == p.second)assert(false);
			answer = min(answer, nans);
			int b;
			b = 1; b++;
		}


	}
private:
	void init(vector<T>&ps, const int& l, const int& r) {
		if (l >= r) {
			return;
		}
		sort(ps.begin() + l, ps.begin() + r, axisSorter<T>(axis));
		const int mid = (l + r) / 2;
		midpo = ps[mid];
		pos = vector<T>(ps.begin() + l, ps.begin() + r);

		ltree = make_kdtree(ps, l, mid, depth + 1);
		
		rtree = make_kdtree(ps, mid + 1, r, depth + 1);
		getmindis();
		if(ltree)ltree->pos.clear();
		if(rtree)rtree->pos.clear();
	}
};


//[l..r)
template<class T>
kdtree<T> *make_kdtree(vector<T>&ps_, const int& l, const int& r, const int& depth = 0) {
	if (l >= r)return nullptr;
	else {
		return new kdtree<T>(ps_, l, r, depth);
	}
}

vector<ld>getunit(vector<int>v) {
	vector<ld>unit;
	ld len = 0;
	for (auto a : v) {
		len += a*a;
		unit.emplace_back(ld(a));
	}
	len = sqrt(len);
	for (auto&u : unit) {
		u /= len;
	}
	return unit;
}
int gcd(int l, int r) {
	assert(l > 0 && r > 0);
	if (l > r)return gcd(r, l);
	else {
		const  int num = r%l;
		if (num) {
			return gcd(l, num);
		}
		else {
			return l;
		}
	}
}
int gcd(vector<int>nums) {
	if (nums.size() == 1)return nums[0];
	int num = nums[0];

	for (int i = 1; i < nums.size(); ++i) {
		num = gcd(num, nums[i]);
	}
	return num;
}

int main() {
	while (1) {
		answer = Ans{ 1e18,make_pair(-1,-1) };
		int M, N, S, W; cin >> M >> N >> S >> W;
		if (!M&&!N&&!S&&!W)break;
		vector<po>pos;
		vector<vector<int>>memo;
		{
			{
				int nx, ny, nz;
				for (int i = 0; i < M; ++i) {
					cin >> nx >> ny >> nz;
					memo.push_back(vector<int>{nx, ny, nz});
				}
				int g = S;
				for (int i = M; i < M + N; ++i) {
					nx = (g / 7) % 100 + 1;
					ny = (g / 700) % 100 + 1;
					nz = (g / 70000) % 100 + 1;
					memo.push_back(vector<int>{nx, ny, nz});
					if (g % 2 == 0)g = g / 2;
					else g = (g / 2) ^ W;
				}
			}
			sort(memo.begin(), memo.end(), [](const vector<int>&l, const vector<int>&r) {
				for (int i = 0; i < 3; ++i) {
					if (l[i] == r[i])continue;
					else return l[i] < r[i];
				}
				return false;
			});
			{
				vector<vector<int>>newmemo;
				map<vector<int>, int>amap;
				for (int i = 0; i < memo.size(); ++i) {
					int agcd = gcd(memo[i]);
					vector<int>v(3);
					for (int j = 0; j < 3; ++j)v[j] = memo[i][j] / agcd;
					if (amap.find(v) == amap.end() || amap[v] > agcd) {
						amap[v] = agcd;
					}
				}
				for (auto m : amap) {
					auto v = m.first;
					for (int i = 0; i < 3; ++i) {
						v[i] *= m.second;
					}
					newmemo.emplace_back(v);
				}
				memo = newmemo;
			}
			sort(memo.begin(), memo.end(), [](const vector<int>&l, const vector<int>&r) {
				for (int i = 0; i < 3; ++i) {
					if (l[i] == r[i])continue;
					else return l[i] < r[i];
				}
				return false;
			});
			for (int i = 0; i < memo.size(); ++i) {
				po p(i, getunit(memo[i]));
				pos.emplace_back(p);
			}
		}

		auto tree = make_kdtree(pos, 0, pos.size(), 0);
		tree->getmindis();
		auto ansp = answer;
		if (ansp.p.first >ansp.p.second)swap(ansp.p.first, ansp.p.second);
		for (int i = 0; i < 3; ++i) {
			cout << memo[answer.p.first][i] << " ";
		}
		for (int i = 0; i < 3; ++i) {
			cout << memo[answer.p.second][i];
			if (i == 2)cout << endl;
			else cout << " ";
		}
		delete(tree);
	}
	return 0;
}
//1524,2763