[BZOJ 5221] [Lydsy2017省队十连测]偏题

10 篇文章 0 订阅
BZOJ传送门

题目描述

斐波那契数列是一个经典递推数列,即 F i b n = F i b n − 1 + F i b n − 2 Fib_n=Fib_{n−1}+Fib_{n−2} Fibn=Fibn1+Fibn2

在这个问题中,定义一个新数列,对于 n ≥ 2 n≥2 n2

F n = F n − 1 + F n − 2 + 2 3 + F n − 1 F n − 2 F_n=F_{n−1}+F_{n−2}+2\sqrt{3+F_{n−1}F_{n−2}} Fn=Fn1+Fn2+23+Fn1Fn2

对于给出的四个整数 F 0 , F 1 , M , n F_0,F_1,M,n F0,F1,M,n,求 F n   m o d   M F_n\ mod\ M Fn mod M

数据保证 3 + F n − 1 F n − 2 \sqrt{3+F_{n−1}F_{n−2}} 3+Fn1Fn2 总是整数。

输入输出格式

输入格式

一行四个整数 F 0 , F 1 , M , n F_0,F_1,M,n F0,F1,M,n

输出格式

一行一个整数,表示 F n F_n Fn M M M取模后的值。

输入输出样例

输入样例#1:
1 1 10 5
输出样例#1:
4
【样例解释1】

F 0 = 1 F_0=1 F0=1

F 1 = 1 F_1=1 F1=1

F 2 = 1 + 1 + 2 3 + 1 × 1 = 6 F_2=1+1+2\sqrt{3+1×1}=6 F2=1+1+23+1×1 =6

F 3 = 6 + 1 + 2 3 + 6 × 1 = 13 F_3=6+1+2\sqrt{3+6×1}=13 F3=6+1+23+6×1 =13

F 4 = 13 + 6 + 2 3 + 13 × 6 = 37 F_4=13+6+2\sqrt{3+13×6}=37 F4=13+6+23+13×6 =37

F 5 = 37 + 13 + 2 3 + 37 × 13 = 94 F_5=37+13+2\sqrt{3+37×13}=94 F5=37+13+23+37×13 =94

输入样例#2
2 3 100 6
输出样例#2
82
数据规模

对于30%的数据, n ≤ 20 n≤20 n20。对于60%的数据, F 0 = F 1 = 1 F_0=F_1=1 F0=F1=1。对于80%的数据, n ≤ 1 0 5 n≤10^5 n105。对于100%的数据, 0 ≤ n ≤ 1 0 9 , 1 ≤ M ≤ 1 0 9 , 1 ≤ F 0 ≤ F 1 ≤ 1 0 6 0≤n≤10_9,1≤M≤10_9,1≤F_0≤F_1≤10_6 0n1091M1091F0F1106

解题分析

我们可以注意到
F n = F n − 1 + F n − 2 + 2 3 + F n − 1 F n − 2 3 + F n F n − 1 = F n − 1 2 + F n − 2 F n − 1 + 2 F n − 1 3 + F n − 1 F n − 2 + 3 3 + F n F n − 1 = 3 + F n − 1 F n − 2 + F n − 1 F_n=F_{n-1}+F_{n-2}+2\sqrt{3+F_{n−1}F_{n−2}} \\ 3+F_nF_{n-1}=F_{n-1}^2+F_{n-2}F_{n-1}+2F_{n-1}\sqrt{3+F_{n−1}F_{n−2}}+3 \\ \sqrt{3+F_nF_{n-1}}=\sqrt{3+F_{n-1}F_{n-2}}+F_{n-1} Fn=Fn1+Fn2+23+Fn1Fn2 3+FnFn1=Fn12+Fn2Fn1+2Fn13+Fn1Fn2 +33+FnFn1 =3+Fn1Fn2 +Fn1

所以我们可以用一个 3 × 3 3\times 3 3×3的矩阵, 分别代表 3 + F n F n − 1 , F n , F n − 1 \sqrt{3+F_nF_{n-1}},F_n, F_n-1 3+FnFn1 ,Fn,Fn1, 就可以矩阵加速递推了。

总复杂度 O ( l o g ( n ) ) O(log(n)) O(log(n))

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
int mod, n, a, b;
struct Matrix {int mat[3][3];};
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
	Matrix ret; std::memset(ret.mat, 0, sizeof(ret.mat));
	for (R int i = 0; i < 3; ++i)
	for (R int j = 0; j < 3; ++j)
	for (R int k = 0; k < 3; ++k)
	ret.mat[i][j] = (ret.mat[i][j] + 1ll * x.mat[i][k] * y.mat[k][j] % mod) % mod;
	return ret;
}
Matrix unit, res, base, ans;
IN Matrix qpow(R int tim)
{
	W (tim)
	{
		if(tim & 1) base = base * res;
		res = res * res, tim >>= 1;
	}
	return base;
}
int main(void)
{
	scanf("%d%d%d%d", &a, &b, &mod, &n);
	if(n == 0) return printf("%d", a), 0;
	if(n == 1) return printf("%d", b), 0;
	n--;
	unit.mat[0][0] = b, unit.mat[1][0] = a, unit.mat[2][0] = (ll)std::sqrt(3 + 1ll * a * b) % mod;
	res.mat[0][0] = 1, res.mat[0][1] = 1, res.mat[0][2] = 2;
	res.mat[1][0] = 1;
	res.mat[2][0] = 1, res.mat[2][2] = 1;
	base.mat[0][0] = base.mat[1][1] = base.mat[2][2] = 1;
	ans = qpow(n);
	ans = ans * unit;
	printf("%d", ans.mat[0][0]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值