Problem:
Score : 600 points

Problem Statement

Given are two sequences a=\{a_0,\ldots,a_{N-1}\} and b=\{b_0,\ldots,b_{N-1}\} of N non-negative integers each.

Snuke will choose an integer k such that 0 \leq k < N and an integer x not less than 0, to make a new sequence of length N, a'=\{a_0',\ldots,a_{N-1}'\}, as follows:

a_i'= a_{i+k \mod N}\ XOR \ x

Find all pairs (k,x) such that a' will be equal to b.

What is \mbox{ XOR }?

The XOR of integers A and B, A \mbox{ XOR } B, is defined as follows:

When A \mbox{ XOR } B is written in base two, the digit in the 2^k's place (k \geq 0) is 1 if either A or B, but not both, has 1 in the 2^k's place, and 0 otherwise.

For example, 3 \mbox{ XOR } 5 = 6. (In base two: 011 \mbox{ XOR } 101 = 110.)

Constraints

1 \leq N \leq 2 \times 10^5

0 \leq a_i,b_i < 2^{30}

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
a_0 a_1 ... a_{N-1}
b_0 b_1 ... b_{N-1}

Output

Print all pairs (k, x) such that a' and b will be equal, using one line for each pair, in ascending order of k (ascending order of x for pairs with the same k).

If there are no such pairs, the output should be empty.

Sample Input 1

3
0 2 1
1 2 3

Sample Output 1

1 3

If (k,x)=(1,3),

a_0'=(a_1\ XOR \ 3)=1

a_1'=(a_2\ XOR \ 3)=2

a_2'=(a_0\ XOR \ 3)=3

and we have a' = b.

Sample Input 2

5
0 0 0 0 0
2 2 2 2 2

Sample Output 2

0 2
1 2
2 2
3 2
4 2

Sample Input 3

6
0 1 3 7 6 4
1 5 4 6 2 3

Sample Output 3

2 2
5 5

Sample Input 4

2
1 2
0 0

Sample Output 4

No pairs may satisfy the condition.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <iostream>
#include <vector>
#include <array>
#include <list>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <string>
#include <sstream>
#include <algorithm>
#include <random>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <cassert>
#include <climits>
#include <bitset>
#include <functional>
#include <iomanip>
#include <random>

#define FOR_LT(i, beg, end) for (int i = beg; i < end; i++)
#define FOR_LE(i, beg, end) for (int i = beg; i <= end; i++)
#define FOR_DW(i, beg, end) for (int i = beg; end <= i; i--)

using namespace std;

class RollingHash
{
public:
	static const uint64_t kM = (1LL << 61) - 1;

	RollingHash(const vector<uint64_t>& vals, const array<uint64_t, 2> rs)
	{
		this->rs_ = rs;

		this->hashs_[0].resize(vals.size() + 1);
		this->hashs_[1].resize(vals.size() + 1);
		this->memop_[0].resize(vals.size() + 1);
		this->memop_[1].resize(vals.size() + 1);

		array<uint64_t, 2> val = { 0, 0 };
		this->hashs_[0][0] = val[0];
		this->hashs_[0][1] = val[1];
		this->memop_[0][0] = 1;
		this->memop_[1][0] = 1;

		FOR_LT(i, 0, (int)vals.size()) {
			val[0] = (Mul(val[0], this->rs_[0]) + vals[i]) % kM;
			val[1] = (Mul(val[1], this->rs_[1]) + vals[i]) % kM;

			this->hashs_[0][i + 1] = val[0];
			this->hashs_[1][i + 1] = val[1];
			this->memop_[0][i + 1] = Mul(this->memop_[0][i], this->rs_[0]) % kM;
			this->memop_[1][i + 1] = Mul(this->memop_[1][i], this->rs_[1]) % kM;
		}
	}
	
	RollingHash(const vector<uint64_t>& vals) : RollingHash(vals, RollingHash::GenerateRs()) {}


	// 先頭 i 文字のハッシュを取得する
	array<uint64_t, 2> Hash(int i) const
	{
		assert(i < (int)this->hashs_[0].size());

		return { this->hashs_[0][i], this->hashs_[1][i] };
	}

	// [i, j) のハッシュを取得する。
	array<uint64_t, 2> Hash(int i, int j) const
	{
		assert(i < j);
		assert(i < (int) this->hashs_[0].size());
		assert(j < (int) this->hashs_[0].size());

		array<uint64_t, 2> hi = this->Hash(i);
		array<uint64_t, 2> hj = this->Hash(j);

		array<uint64_t, 2> ret = {
			(hj[0] + kM - Mul(hi[0], this->memop_[0][j - i]) % kM) % kM,
			(hj[1] + kM - Mul(hi[1], this->memop_[1][j - i]) % kM) % kM
		};

		return ret;
	}

	static uint64_t AddOnM(uint64_t a, uint64_t b)
	{
		return (a + b) % kM;
	}

	static uint64_t MulOnM(uint64_t a, uint64_t b)
	{
		return Mul(a, b) % kM;
	}

	const array<uint64_t, 2>& Rs() const {
		return this->rs_;
	}

	const array<vector<uint64_t>, 2>& MomoP() const {
		return this->memop_;
	}

	int N() const {
		return (int) (this->hashs_[0].size() - 1);
	}

	static array<uint64_t, 2> GenerateRs()
	{
		array<uint64_t, 2> rs;
		random_device seed;
		mt19937_64 mt(seed());
		for (auto& r : rs) {
			r = mt() % (kM >> 30) + 1001;
		}

		return rs;
	}

private:
	static uint64_t Mul(uint64_t a, uint64_t b)
	{
		uint64_t au = a >> 31;
		uint64_t ad = a & ((1UL << 31) - 1);
		uint64_t bu = b >> 31;
		uint64_t bd = b & ((1UL << 31) - 1);

		uint64_t cval = au * bd + ad * bu;
		uint64_t cu   = (cval >> 30);
		uint64_t cd   = cval & ((1UL << 30) - 1);

		return au * bu * 2 + cu + (cd << 31) + ad * bd;
	}

	array<vector<uint64_t>, 2> hashs_;
	array<uint64_t, 2> rs_;
	array<vector<uint64_t>, 2> memop_;

};

static array<uint64_t, 2> CalcHash(const RollingHash& rh, int s)
{
	array<uint64_t, 2> hh = rh.Hash(s, rh.N());
	array<uint64_t, 2> hl = rh.Hash(s);

	return {
		RollingHash::AddOnM(hl[0], RollingHash::MulOnM(hh[0], rh.MomoP()[0][s])),
		RollingHash::AddOnM(hl[1], RollingHash::MulOnM(hh[1], rh.MomoP()[1][s]))
	};
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout << fixed << setprecision(20);

	int n; cin >> n;
	vector<uint64_t> as(n); for (auto& a : as) cin >> a;
	vector<uint64_t> bs(n); for (auto& b : bs) cin >> b;

	vector<uint64_t> das(n);
	vector<uint64_t> dbs(n);
	FOR_LT(i, 0, n - 1) {
		das[i] = as[i + 1] ^ as[i];
		dbs[i] = bs[i + 1] ^ bs[i];
	}
	das[n - 1] = as[0] ^ as[n - 1];
	dbs[n - 1] = bs[0] ^ bs[n - 1];

	array<uint64_t, 2> rs = RollingHash::GenerateRs();
	RollingHash arh(das, rs);
	RollingHash brh(dbs, rs);

	FOR_LT(i, 0, n) {
		array<uint64_t, 2> aa = CalcHash(arh, i);
		array<uint64_t, 2> ba = CalcHash(brh, 0);

		if (aa == ba) {
			cout << i << " " << (as[i] ^ bs[0]) << endl;
		}
	}

	return 0;
}