[做题记录-乱做] BZOJ 3328 PYXFIB

题意

\[\sum_{i = 0}^{n} \binom{n}{i}f_i[k | i] \]

\(n \leq 10^{18}, k \leq 20000, T \leq 20\)

\(f\)是斐波那契数。

题解

单位根反演

\[[k|n] = \frac{1}{k}\sum_{i = 0}^{k - 1}w_k^{ni} \]

找原根

  • 分解\(P - 1\)

  • 枚举一个数\(a\)

  • 对于每一个质因子\(i\), 判断\(a^{(P - 1)/ i}\)是否为\(1\)

  • 如果对于每一个质因子上面的测试都不是\(1\), 那就找到了一个原根\(a\)

  • 2的原根是\(1\)

  • 原根的所有幂次在剩余系下的取值给出所有原根。

题解

搞个矩阵\(A\)表示斐波那契的转移矩阵, 考虑化式子。

\[\sum_{i = 0}^n\binom{n}{i}f_i(\frac{1}{k}\sum_{j = 0}^{k - 1}w_k^{ij}) \\ =\frac{1}{k}\sum_{j = 0}^{k - 1}\sum_{i = 0}^n\binom{n}{i}(Aw_{k}^j)^i \\ =\frac{1}{k}\sum_{j = 0}^{k - 1}(Aw_k^j+I)^n \]

求出原根然后算就完了。

#include <bits/stdc++.h>

using namespace std;

namespace IO {
	char a; int f;
	template<typename T> inline void read(T &x) {
		x = 0; f = 1; a = getchar();
		for(; ! isdigit(a); a = getchar()) if(a == '-') f = -1;
		for(; isdigit(a); a = getchar()) x = x * 10 + a - '0';
		x *= f;
	}
	template <typename T> inline void write(T x) {
		if(x > 9) write(x / 10);
		putchar(x % 10 + '0');
	}
} 

using IO :: read;
using IO :: write;

int P = 998244353;
inline int mod(int x) { return x + ((x >> 31) & P); }
inline void pls(int &x, int y) { x = mod(x + y - P); }
inline void dec(int &x, int y) { x = mod(x - y); }
inline int power(int x, int k) {
	int res = 1;
//	cerr << k << endl;
	while(k) {
		if(k & 1) res = 1ll * res * x % P;
		x = 1ll * x * x % P; k >>= 1;
	} return res;
}

#define lep(i, l, r) for(int i = (l); i <= (r); i ++)
#define rep(i, l, r) for(int i = (l); i >= (r); i --)

using i64 = long long;
using i128 = __int128;
using uint = unsigned int;
using ui64 = unsigned long long;

struct Mat {
	int a[2][2];
	Mat() { a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0; }
	Mat(int _a, int _b, int _c, int _d) {
		a[0][0] = _a; a[0][1] = _b; a[1][0] = _c; a[1][1] = _d;
	}
	inline Mat operator *(const Mat &t) const {
		Mat r;
		lep (i, 0, 1)
			lep (j, 0, 1) 
				lep (k, 0, 1)
					r.a[i][j] = (r.a[i][j] + 1ll * a[i][k] * t.a[k][j]) % P;
		return r;
	}
	inline Mat operator ^(i64 k) {
		Mat res(1, 0, 0, 1);
		Mat x = *this;
		while(k) {
			if(k & 1) res = res * x;
			x = x * x; k >>= 1;
		}
		return res;
	}
} ;

const Mat I = Mat(1, 0, 0, 1);

int k, p;
i64 n;

int findroot(int p) {
	if(p == 2) return 1;
	vector<int> factor;
	int t = p;
	p --;
	for(int i = 2; i * i <= p; i ++)
		if(p % i == 0) {
			factor.push_back(i);
			while(p % i == 0) p /= i;
		}
	if(p > 1) factor.push_back(p);
	//cerr << factor.size() << endl;
	p = t;
	lep (a, 2, p - 1) {
		int fail = 0;
		lep (j, 0, factor.size() - 1) {
			int i = factor[j];
			//cerr << i << endl;
			//cerr << power(a, (P - 1) / i) << endl;
	//		cerr << a << ' ' << i << ' ' << power(a, (p - 1) / i) << endl;
			if(power(a, (P - 1) / i) == 1) { fail = 1; break; }
		}
		if(! fail) return a;
	}
	return -1;
}

void solve() {//return ;
	read(n); read(k); read(p);
	P = p; //cerr << P << endl; 
	int g = findroot(p); //cerr << g << endl;
	
	int w = power(g, (P - 1) / k);
	int ans = 0;
	Mat A(1, 1, 1, 0);
	int W = 1;
	lep (j, 0, k - 1) {
		Mat F = A;
		lep (x, 0, 1)
			lep (y, 0, 1)
				F.a[x][y] = 1ll * F.a[x][y] * W % P;
		F.a[0][0] ++; F.a[1][1] ++;
		F = F ^ n;
		ans = (ans + F.a[0][0]) % P;
		W = 1ll * W * w % P;
	}
	ans = 1ll * ans * power(k, P - 2) % P;
	write(ans);
	putchar('\n');
}

signed main() {
	//freopen(".in", "r", stdin);
	//freopen(".out", "w", stdout);
//	P = p;
//	cerr << findroot(5) << endl;
//	return 0;
	int Case; read(Case);
	while(Case --) solve();
	return 0;
}
posted @ 2021-10-08 20:05  HN-wrp  阅读(31)  评论(0编辑  收藏  举报