BZOJ 4002: [JLOI2015]有意义的字符串

看到式子的形式,可以想到斐波那契数列的通项的形式
\(f_n = \left(\dfrac{b+\sqrt d}{2}\right)^n + \left(\dfrac{b-\sqrt d}{2}\right)^n\)
这两个是方程 \(x^2-bx+\dfrac{b^2-d}{4}=0\) 的两根
根据特征方程及特征根可以得到递推式 $$f_n=bf_{n-1}-\frac{b^2-d}{4}f_{n-2}$$
两个系数都是整数,那么可以矩阵快速幂得到 \(f_n\) 的值
\(\text{ans}=f_n - \left(\dfrac{b-\sqrt d}{2}\right)^n\)
\(n\) 为奇数时,下取整右半部分为 \(0\)
\(n\) 为偶数时,下取整右半部分为 \(-1\)

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const ll MOD = 7528443412579576937ll;
void M(ll &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }

ll add(ll x, ll y) {
	ull z = ull(x) + ull(y);
	return z >= MOD ? z - MOD : z;
}
ll mul(ll a, ll b) {
	ll ans = 0;
	while (b) {
		if (b & 1) ans = add(ans, a);
		a = add(a, a);
		b >>= 1;
	}
	return ans;
}
struct Mat {
	ll mat[2][2];
	Mat() { memset(mat, 0, sizeof(mat)); }
	Mat operator * (const Mat &p) const {
		Mat c;
		rep (i, 0, 2)
			rep (j, 0, 2)
				rep (k, 0, 2)
					c.mat[i][j] = add(c.mat[i][j], mul(mat[i][k], p.mat[k][j]));
		return c;
	}
};

Mat qp(Mat a, ll b) {
	Mat res;
	res.mat[0][0] = res.mat[1][1] = 1;
	while (b) {
		if (b & 1) res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}

int main() {
	ll b, d, n;
	scanf("%lld%lld%lld", &b, &d, &n);
	if (n == 0) {
		puts("1");
		return 0;
	}
	Mat res;
	res.mat[0][0] = b; res.mat[0][1] = MOD - ((b * b - d) >> 2);
	res.mat[1][0] = 1;
	res = qp(res, n - 1);
	ll ans = add(mul(res.mat[0][0], b), mul(res.mat[0][1], 2));
	if (n % 2 == 0) ans--;
	if (ans < 0) ans += MOD;
	printf("%lld\n", ans);
	return 0;
}
posted @ 2020-02-24 20:48  Mrzdtz220  阅读(111)  评论(0编辑  收藏  举报