QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#617441#9225. Fibonacci Fusionucup-team5062#TL 2659ms15644kbC++177.7kb2024-10-06 15:34:422024-10-06 15:34:43

Judging History

你现在查看的是最新测评结果

  • [2024-10-06 15:34:43]
  • 评测
  • 测评结果:TL
  • 用时:2659ms
  • 内存:15644kb
  • [2024-10-06 15:34:42]
  • 提交

answer

#include <array>
#include <cmath>
#include <vector>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <algorithm>
using namespace std;

const uint64_t MOD = 18446744069414584321ULL;

class modint {
private:
	uint64_t x;
public:
	modint() : x(0) {}
	modint(uint64_t x_) : x(x_) {}
	uint64_t val() const { return x; }
	modint& operator+=(const modint& m) {
		uint64_t y = x + m.x;
		x = (y >= x ? y : y - MOD);
		return *this;
	}
	modint& operator-=(const modint& m) {
		uint64_t y = x - m.x;
		x = (y <= x ? y : y + MOD);
		return *this;
	}
	modint& operator*=(const modint& m) {
		__uint128_t y = __uint128_t(x) * m.x;
		x = y % MOD; // TODO: MAKE IT FASTER!
		return *this;
	}
	modint operator+(const modint& m) const {
		return modint(*this) += m;
	}
	modint operator-(const modint& m) const {
		return modint(*this) -= m;
	}
	modint operator*(const modint& m) const {
		return modint(*this) *= m;
	}
	modint pow(uint64_t b) const {
		modint res(1), a(*this);
		while (b != 0) {
			if (b & 1) {
				res *= a;
			}
			a *= a;
			b >>= 1;
		}
		return res;
	}
	modint inv() const {
		return pow(MOD - 2);
	}
};

const modint GEN = modint(7);
const modint GEN_INV = modint(7).inv();

vector<modint> fft(int n, const vector<modint>& x, bool inv) {
	// step #1. preparation
	modint root = (!inv ? GEN : GEN_INV);
	vector<modint> z(n);
	for (int i = 0; i < n; i++) {
		int r1 = 1, r2 = n / 2, cur = 0;
		while (r2 >= 1) {
			if ((i & r1) != 0) {
				cur += r2;
			}
			r1 <<= 1;
			r2 >>= 1;
		}
		z[cur] = x[i];
	}

	// step #2. calculation
	for (int b = 2; b <= n; b *= 2) {
		vector<modint> pows(b);
		pows[0] = 1;
		pows[1] = root.pow((MOD - 1) / b);
		for (int i = 2; i < b; i++) {
			pows[i] = pows[i - 1] * pows[1];
		}
		for (int stt = 0; stt < n; stt += b) {
			for (int i = 0; i < b / 2; i++) {
				modint r1 = z[stt + i] + pows[i + 0 * b / 2] * z[stt + i + b / 2];
				modint r2 = z[stt + i] + pows[i + 1 * b / 2] * z[stt + i + b / 2];
				z[stt + i + 0 * b / 2] = r1;
				z[stt + i + 1 * b / 2] = r2;
			}
		}
	}

	// step #3. finalize
	if (inv) {
		modint SCALE = modint(n).inv();
		for (int i = 0; i < n; i++) {
			z[i] *= SCALE;
		}
	}
	
	return z;
}

vector<int64_t> convolution_unsigned(const vector<int32_t>& a, const vector<int32_t>& b) {
	int n = int(a.size()) + int(b.size()) - 1;
	int sz = (n >= 2 ? 1 << (32 - __builtin_clz(n - 1)) : 1);
	vector<modint> va(sz), vb(sz);
	for (int i = 0; i < int(a.size()); i++) {
		va[i] = a[i];
	}
	for (int i = 0; i < int(b.size()); i++) {
		vb[i] = b[i];
	}
	va = fft(sz, va, false);
	vb = fft(sz, vb, false);
	for (int i = 0; i < sz; i++) {
		va[i] *= vb[i];
	}
	va = fft(sz, va, true);
	vector<int64_t> c(n);
	for (int i = 0; i < n; i++) {
		c[i] = va[i].val();
	}
	return c;
}

const int DIGITS = 6;
const int DIGITS_POW = 1'000'000;

class bigint {
private:
	int size;
	vector<int32_t> v;
	void normalize() {
		while (size >= 2 && v.back() == 0) {
			v.pop_back();
			size--;
		}
	}
public:
	explicit bigint() : v() {}
	explicit bigint(const string& s) {
		size = (s.size() + DIGITS - 1) / DIGITS;
		v = vector<int32_t>(size, 0);
		for (int i = 0; i < int(s.size()); i++) {
			int idx = (s.size() - i - 1) / DIGITS;
			v[idx] = v[idx] * 10 + int(s[i] - '0');
		}
		normalize();
	}
	string to_string() const {
		string res;
		for (int i = 0; i < size; i++) {
			int x = v[i];
			for (int j = 0; j < DIGITS; j++) {
				res += char(x % 10 + '0');
				x /= 10;
			}
		}
		while (int(res.size()) >= 2 && res.back() == '0') {
			res.pop_back();
		}
		reverse(res.begin(), res.end());
		return res;
	}
	bool operator==(const bigint& b) const {
		return v == b.v;
	}
	bool operator!=(const bigint& b) const {
		return v != b.v;
	}
	bool operator<(const bigint& b) const {
		if (size != b.size) {
			return size < b.size;
		}
		for (int i = size - 1; i >= 0; i--) {
			if (v[i] != b.v[i]) {
				return v[i] < b.v[i];
			}
		}
		return false;
	}
	bool operator>(const bigint& b) const {
		if (size != b.size) {
			return size > b.size;
		}
		for (int i = size - 1; i >= 0; i--) {
			if (v[i] != b.v[i]) {
				return v[i] > b.v[i];
			}
		}
		return false;
	}
	bool operator<=(const bigint& b) const {
		if (size != b.size) {
			return size < b.size;
		}
		for (int i = size - 1; i >= 0; i--) {
			if (v[i] != b.v[i]) {
				return v[i] < b.v[i];
			}
		}
		return true;
	}
	bool operator>=(const bigint& b) const {
		if (size != b.size) {
			return size > b.size;
		}
		for (int i = size - 1; i >= 0; i--) {
			if (v[i] != b.v[i]) {
				return v[i] > b.v[i];
			}
		}
		return true;
	}
	bigint& operator+=(const bigint& b) {
		if (size < b.size) {
			v.resize(b.size);
			size = b.size;
		}
		int carry = 0;
		for (int i = 0; i < size; i++) {
			v[i] += (i < b.size ? b.v[i] : 0) + carry;
			if (v[i] >= DIGITS_POW) {
				v[i] -= DIGITS_POW;
				carry = 1;
			} else {
				carry = 0;
			}
		}
		if (carry == 1) {
			v.push_back(1);
			size += 1;
		}
		return *this;
	}
	bigint& operator-=(const bigint& b) {
		assert(size >= b.size);
		int carry = 0;
		for (int i = 0; i < size; i++) {
			v[i] -= (i < b.size ? b.v[i] : 0) + carry;
			if (v[i] < 0) {
				v[i] += DIGITS_POW;
				carry = 1;
			} else {
				carry = 0;
			}
		}
		assert(carry == 0);
		normalize();
		return *this;
	}
	bigint& operator*=(const bigint& b) {
		vector<int64_t> res = convolution_unsigned(v, b.v);
		for (int i = 0; i < int(res.size()); i++) {
			if (i == int(res.size()) - 1 && res[i] >= DIGITS_POW) {
				res.push_back(0);
			}
			res[i + 1] += res[i] / DIGITS_POW;
			res[i] %= DIGITS_POW;
		}
		size = res.size();
		v.resize(size);
		for (int i = 0; i < size; i++) {
			v[i] = res[i];
		}
		normalize();
		return *this;
	}
	bigint operator+(const bigint& b) const {
		return bigint(*this) += b;
	}
	bigint operator-(const bigint& b) const {
		return bigint(*this) -= b;
	}
	bigint operator*(const bigint& b) const {
		return bigint(*this) *= b;
	}
	double log10() const {
		double p = 0.0, q = 1.0;
		for (int i = size - 1; i >= 0; i--) {
			p += v[i] * q;
			q /= DIGITS_POW;
		}
		return (size - 1) * DIGITS + std::log10(p);
	}
};

array<bigint, 2> fib(int n) {
	if (n == 0) {
		return {bigint("0"), bigint("1")};
	}
	array<bigint, 2> z = fib(n / 2);
	bigint a = z[0] * z[0];
	bigint b = z[0] * z[1];
	bigint c = z[1] * z[1];
	if (n % 2 == 0) {
		return {b + b - a, a + c};
	}
	return {a + c, b + b + c};
}

int fib_index(double x) {
	// n = 10^x
	double z = x + log10(5) / 2;
	double logphi = log10((1 + sqrt(5)) / 2);
	return z / logphi + 0.8;
}

long long solve(int N, vector<bigint>& A) {
	// step #1. sort and compress
	sort(A.begin(), A.end());
	vector<bigint> B;
	vector<int> C;
	int pre = 0;
	for (int i = 1; i <= N; i++) {
		if (i == N || A[i] != A[i - 1]) {
			B.push_back(A[i - 1]);
			C.push_back(i - pre);
			pre = i;
		}
	}
	int Z = B.size();

	// step #2. check answer
	long long ans = 0;
	for (int i = 0; i < Z; i++) {
		int x = fib_index(B[i].log10());
		array<bigint, 2> val = fib(x);
		for (int j = 0; j < 2; j++) {
			if (B[i] <= val[j] && val[j] < B[i] + B[i]) {
				bigint target = val[j] - B[i];
				int pos = lower_bound(B.begin(), B.end(), target) - B.begin();
				if (B[pos] == target) {
					ans += 1LL * C[i] * C[pos];
				}
			} else if (val[j] == B[i] + B[i]) {
				ans += 1LL * C[i] * (C[i] - 1) / 2;
			}
		}
	}

	return ans;
}

int main() {
	int N;
	cin >> N;
	vector<bigint> A(N);
	for (int i = 0; i < N; i++) {
		string str;
		cin >> str;
		A[i] = bigint(str);
	}
	long long ans = solve(N, A);
	cout << ans << endl;
	return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3740kb

input:

6
50
8
8
5
72
354224848179261915070

output:

4

result:

ok 1 number(s): "4"

Test #2:

score: 0
Accepted
time: 2659ms
memory: 11580kb

input:

28
200878223506436882933619847964496455022155117513398820563747455993172799881403389571477889821109288771413214004090719097929400406252135763028179112130390003528046316900603668569910008417315162907579003880220844686222148696041857432602133894827753998572080650383305777912447151917272483538029469449...

output:

27

result:

ok 1 number(s): "27"

Test #3:

score: 0
Accepted
time: 2438ms
memory: 10384kb

input:

5187
2640352926124261912741724778991366987330659389621881876017670644497364093930668042530271338851702874394631009332660937266680740235862107353443518003194307853104942996827176097428402408674756368623972812842571069642405111849826172879369776309763468485788964245903781380419155348915131587410703749...

output:

6073

result:

ok 1 number(s): "6073"

Test #4:

score: 0
Accepted
time: 32ms
memory: 15644kb

input:

200000
2
2
2
2
1
2
1
1
2
2
1
1
1
2
2
1
1
2
1
1
2
2
1
2
2
2
1
1
1
1
2
2
1
2
1
2
1
1
2
2
1
1
1
2
1
1
2
1
2
2
2
2
1
2
2
1
1
1
2
1
1
1
1
1
2
1
2
2
1
1
1
2
2
2
1
1
2
1
1
2
1
2
1
1
1
2
2
2
1
1
1
1
2
1
2
1
1
2
2
1
1
2
1
1
2
1
2
2
1
2
1
2
2
1
1
2
1
1
1
2
2
2
1
2
2
1
1
2
2
2
2
1
2
1
1
2
1
2
2
1
1
1
1
2
2
2
2...

output:

15003749259

result:

ok 1 number(s): "15003749259"

Test #5:

score: -100
Time Limit Exceeded

input:

200000
944176313232170622314
2590599414036674999101
753315073608896000424
9299685298577430049245
9361800333778142620806
8988699166328904060999
9606920674025578304023
4203331868598952026136
5183047027116137697788
3968714342776915029801
8130984095583566992354
3206443643596048048798
6248561214283254355...

output:


result: