【BZOJ3328】PYXFIB

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89517115

【题目链接】

【思路要点】

  • 注意到 i = 0 N ( N i ) x i = ( x + 1 ) N \sum_{i=0}^{N}\binom{N}{i}x^i=(x+1)^N F i = ( m a t i ) 1 , 1 F_i=(mat^i)_{1,1} ,其中 m a t = { { 0 , 1 } , { 1 , 1 } } mat=\{\{0,1\},\{1,1\}\} ,因此有
    i = 0 N ( N i ) × F i = ( ( m a t + I ) N ) 1 , 1 \sum_{i=0}^{N}\binom{N}{i}\times F_i=((mat+I)^N)_{1,1}
  • 答案即为 i = 0 N ( N i ) × F i × [ k i ] \sum_{i=0}^{N}\binom{N}{i}\times F_i\times[k\mid i]
    = 1 k i = 0 N ( N i ) × F i j = 0 k 1 w k i j =\frac{1}{k}\sum_{i=0}^{N}\binom{N}{i}\times F_i\sum_{j=0}^{k-1}w_k^{ij}
    = 1 k j = 0 k 1 ( ( w k j m a t + I ) N ) 1 , 1 =\frac{1}{k}\sum_{j=0}^{k-1}((w_k^jmat+I)^N)_{1,1}
  • 时间复杂度 O ( K L o g N ) O(KLogN)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
ll n; int k, g, w, P;
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
bool PrimitiveRoot(int g) {
	int phi = P - 1;
	for (int i = 2; i * i <= phi; i++)
		if (phi % i == 0) {
			while (phi % i == 0) phi /= i;
			if (power(g, (P - 1) / i) == 1) return false;
		}
	if (phi != 1 && power(g, (P - 1) / phi) == 1) return false;
	return true;
}
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
int getans(int d) {
	static int cur[2][2], res[2][2], tmp[2][2];
	for (int i = 0; i <= 1; i++)
	for (int j = 0; j <= 1; j++) {
		res[i][j] = i == j;
		cur[i][j] = d * (i + j != 0) + (i == j);
		if (cur[i][j] >= P) cur[i][j] -= P;
	}
	ll lft = n;
	for (ll p = 1; lft != 0; p <<= 1) {
		if (lft & p) {
			lft ^= p;
			for (int i = 0; i <= 1; i++)
			for (int j = 0; j <= 1; j++) {
				ll tres = 0;
				for (int k = 0; k <= 1; k++)
					tres += 1ll * res[i][k] * cur[k][j];
				tmp[i][j] = tres % P;
			}
			memcpy(res, tmp, sizeof(res));
		}
		for (int i = 0; i <= 1; i++)
		for (int j = 0; j <= 1; j++) {
			ll tres = 0;
			for (int k = 0; k <= 1; k++)
				tres += 1ll * cur[i][k] * cur[k][j];
			tmp[i][j] = tres % P;
		}
		memcpy(cur, tmp, sizeof(cur));
	}
	return res[1][1];
}
int main() {
	int T; read(T);
	while (T--) {
		read(n), read(k), read(P);
		g = 2; while (!PrimitiveRoot(g)) g++; w = power(g, (P - 1) / k);
		int ans = 0, now = 1;
		for (int i = 0; i <= k - 1; i++) {
			update(ans, getans(now));
			now = 1ll * now * w % P;
		}
		writeln(1ll * ans * power(k, P - 2) % P);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/89517115