結果

問題 No.980 Fibonacci Convolution Hard
ユーザー QCFiumQCFium
提出日時 2020-01-31 22:29:01
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
TLE  
実行時間 -
コード長 3,190 bytes
コンパイル時間 2,045 ms
コンパイル使用メモリ 182,196 KB
実行使用メモリ 217,388 KB
最終ジャッジ日時 2024-09-17 09:04:53
合計ジャッジ時間 44,269 ms
ジャッジサーバーID
(参考情報)
judge2 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 TLE -
testcase_01 TLE -
testcase_02 TLE -
testcase_03 TLE -
testcase_04 TLE -
testcase_05 TLE -
testcase_06 TLE -
testcase_07 TLE -
testcase_08 TLE -
testcase_09 TLE -
testcase_10 TLE -
testcase_11 TLE -
testcase_12 TLE -
testcase_13 TLE -
testcase_14 TLE -
testcase_15 TLE -
testcase_16 TLE -
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}

template<int mod, int proot> struct NTT {
	int get_mod() { return mod; }
	int pow(int a, int b) {
	int res = 1;
		for (; b; b >>= 1) {
			if (b & 1) res = (int64_t) res * a % mod;
			a = (int64_t) a * a % mod;
		}
		return res;
	}
	int inv(int i) { return pow(i, mod - 2); }
	void ntt(std::vector<int> &a, bool inverse) {
		int n = a.size();
		assert((n & -n) == n);
		int h = pow(proot, (mod - 1) / n);
		if (inverse) h = inv(h);
		
		for (int i = 0, j = 1; j < n - 1; j++) {
			for (int k = n >> 1; k > (i ^= k); k >>= 1);
			if (j < i) std::swap(a[i], a[j]);
		}
		for (int i = 1; i < n; i <<= 1) {
			int base = pow(h, n / i / 2);
			int w = 1;
			
			std::vector<int> ws(i);
			for (int j = 0; j < i; j++) ws[j] = w, w = (int64_t) w * base % mod;
			
			for (int j = 0; j < n; j += i << 1) {
				for (int k = 0; k < i; k++) {
					int u = a[k + j];
					int d = (int64_t) a[k + j + i] * ws[k] % mod;
					a[k + j] = u + d >= mod ? u + d - mod : u + d;
					a[k + j + i] = d > u ? u + mod - d : u - d;
				}
			}
		}
		if (inverse) {
			int ninv = inv(a.size());
			for (auto &i : a) i = (int64_t) i * ninv % mod;
		}
	}
	std::vector<int> conv(const std::vector<int> a_, const std::vector<int> b_) {
		std::vector<int> a = a_, b = b_;
		size_t size = 1;
		for (; size < a_.size() + b_.size(); size <<= 1);
		a.resize(size);
		b.resize(size);
		ntt(a, false);
		ntt(b, false);
		for (size_t i = 0; i < size; i++) a[i] = (int64_t) a[i] * b[i] % mod;
		ntt(a, true);
		a.resize(a_.size() + b_.size() - 1);
		return a;
	}
};

template<int mod>
int64_t inv(int64_t a) {
	a %= mod;
	int res = 1;
	for (int x = mod - 2; x; x >>= 1) {
		if (x & 1) res = (int64_t) res * a % mod;
		a = (int64_t) a * a % mod;
	}
	return res;
}

#define MOD 1000000007
// copied from https://math314.hateblo.jp/entry/2015/05/07/014908
std::vector<int64_t> conv_mod(std::vector<int> a, std::vector<int> b){
	NTT<935329793, 3> ntt1;
	NTT<943718401, 7> ntt2;
	NTT<998244353, 3> ntt3;
	auto x_ = ntt1.conv(a, b);
	auto y_ = ntt2.conv(a, b);
	auto z_ = ntt3.conv(a, b);
	std::vector<int64_t> x, y, z;
	for (auto i : x_) x.push_back(i);
	for (auto i : y_) y.push_back(i);
	for (auto i : z_) z.push_back(i);
	
	// garnerのアルゴリズムを極力高速化した
	constexpr int64_t m1 = 935329793, m2 = 943718401, m3 = 998244353;
	const int64_t m1_inv_m2 = inv<m2>(m1);
	const int64_t m12_inv_m3 = inv<m3>(m1 * m2);
	const int64_t m12_mod = m1 * m2 % MOD;
	std::vector<int64_t> ret(x.size());
	for (int i = 0; i < (int) x.size(); i++) {
		int64_t v1 = (y[i] - x[i]) * m1_inv_m2 % m2;
		if (v1 < 0) v1 += m2;
		int64_t v2 = (z[i] - (x[i] + m1 * v1) % m3) * m12_inv_m3 % m3;
		if (v2 < 0) v2 += m3;
		int64_t constants3 = (x[i] + m1 * v1 + m12_mod * v2) % MOD;
		if (constants3 < 0) constants3 += MOD;
		ret[i] = constants3;
	}

	return ret;
}

int main() {
	int p = ri();
	std::vector<int> a(2000001);
	a[1] = 0;
	a[2] = 1;
	for (int i = 3; i <= 2000000; i++) a[i] = ((int64_t) a[i - 1] * p + a[i - 2]) % MOD;
	
	auto res = conv_mod(a, a);
	
	int q = ri();
	for (int i = 0; i < q; i++) {
		printf("%d\n", (int) res[ri()]);
	}
  	return 0;
}
0