2020牛客寒假算法基础集训营1——J.u's的影响力【矩阵快速幂 & 欧拉降幂】(附加强数据 & 注意坑点)

题目传送门


题目描述

本题测试样例已经更(jia)新(qiang)。

μ’s在九人齐心协力下,影响力越来越大了!
已知第一天影响力为 x x ,第二天影响力为 y y ,从第三天开始,每一天的影响力为前两天影响力的乘积再乘以 a a b b 次方。 用数学语言描述是:
设第 i i 天的影响力为 f ( i ) f(i) ,那么 f ( 1 ) = x f(1)=x f ( 2 ) = y f(2)=y ,对于 i > 2 i>2 f ( i ) = f ( i 1 ) f ( i 2 ) a b f(i)=f(i-1)*f(i-2)*a^b
她们想知道第 n n 天影响力是多少?
由于这个数可能非常大,只需要输出其对 1000000007 1000000007 取模的值就可以了。


输入描述:

一行五个正整数: n , x , y , a , b n,x,y,a,b
( 1 < = n , x , y , a , b < = 1 0 12 ) (1<=n,x,y,a,b<=10^{12})


输出描述:

n n 天的影响力对 1000000007 1000000007 取模的值。


输入

4 2 3 2 1


输出

72


说明

f(1)=2,f(2)=3,f(3)=f(1)*f(2)*2=12,f(4)=f(2)*f(3)*2=72

备注:

1000000007是素数。


题解

  • 显然 f ( n ) f(n) 可以用 x x , y y a a 这三个因子表达出来。
    每一项a的幂次分别是 0 0 b 2 b 4 b 7 b 12 b 0、0、b、2b、4b、7b、12b…… 从第三项开始每一项为前两项之和加1。
    x x y y 的幂次构成斐波那契数列: x x 的幂次第一项是 1 1 ,第二项是 0 0 y y 的幂次第一项是 0 0 ,第二项是 1 1 。之后每一项均为前两项之和。
  • 根据费马小定理,由于 1 e 9 + 7 1e9+7 是素数,有 a 1 e 9 + 6 1 ( m o d 1 e 9 + 7 ) {a\mathop{{}}\nolimits^{{1e9+6{\text{ }}}} \equiv 1 \left( mod\text{ }1e9+7 \right) } 。因此幂的指数对 1 e 9 + 6 1e9+6 取模即可。要注意a是1000000007的倍数的特殊情况。
  • 可以用矩阵快速幂 O ( l o g n ) O(logn) 求出 x y a x、y、a 幂次的第 n n 项。
  • c f 2200 参考cf难度分:2200

特别注意(赛后加强数据)

  • 注意 x % ( 1 e 9 + 7 ) = 0 x 0 0 q _ p o w ( 0 , 0 ) 1 0 0 x\%(1e9+7)=0时,并且x的次幂也为0时,正确答案应该是0,但是由于q\_pow(0,0)返回的是1,会导致答案非0。所以要防止幂为0的特殊情况。
    提供数据:1000000010 1000000007 3 5 1
  • a b b m o d 1 0 先计算a的b次方可以避免b模mod-1为0的情况

AC-Code

#include <bits/stdc++.h>
//#pragma GCC optimize("O3")
//#pragma G++ optimize("O3")
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define ll long long
#define RI register int 
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int maxn = 3;
const int mod = 1e9 + 7;

struct mat {
	int m[maxn][maxn];
	mat() {
		memset(m, 0, sizeof m);
	}
}unit;

mat operator * (mat a, mat b) {
	mat ret;
	ll x;
	for (ll i = 0; i < maxn; ++i)
		for (ll j = 0; j < maxn; ++j) {
			x = 0;
			for (ll k = 0; k < maxn; ++k)
				x += ((ll)a.m[i][k] * b.m[k][j]) % (mod - 1);
			ret.m[i][j] = x % (mod - 1);
		}
	return ret;
}

void init_unit() {
	for (int i = 0; i < maxn; ++i)
		unit.m[i][i] = 1;
}

mat pow_mat(mat a, ll n) {
	mat ret = unit;
	while (n) {
		if (n & 1)	ret = ret * a;
		a = a * a;
		n >>= 1;
	}
	return ret;
}

ll q_mult(ll a, ll b, ll k) {
	ll res = 0;
	while (b) {
		if (b & 1)	res = (res + a) % k;
		a = (a + a) % k;
		b >>= 1;
	}
	return res;
}

ll q_pow(ll a, ll n, ll k) {
	ll res = 1;
	while (n) {
		if (n & 1)	res = q_mult(res, a, k);
		a = (a * a) % k;
		n >>= 1;
	}
	return res;
}

int main() {
	ios;
	init_unit();
	ll n, x, y, a, b;
	while (cin >> n >> x >> y >> a >> b) {

		a = q_pow(a % mod, b, mod);
		x = x % mod;
		y = y % mod;
		if (n == 1) {
			cout << x << endl;
		}
		else if (n == 2) {
			cout << y << endl;
		}
		else if (n == 3) {
			cout << q_mult(q_mult(x, y, mod), a % mod, mod) << endl;
		}
		else {
			mat mat_a, mat_b;
			mat_b.m[0][0] = 1, mat_b.m[0][1] = 1, mat_b.m[0][2] = 0;
			mat_b.m[1][0] = 1, mat_b.m[1][1] = 0, mat_b.m[1][2] = 1;
			mat_b.m[2][0] = 0, mat_b.m[2][1] = 0, mat_b.m[2][2] = 0;

			mat_a.m[0][0] = 1, mat_a.m[0][1] = 1, mat_a.m[0][2] = 0;

			ll z1 = (mat_a * pow_mat(mat_b, n - 4)).m[0][0];
			ll z2 = (mat_a * pow_mat(mat_b, n - 3)).m[0][0];
			ll z3 = (mat_a * pow_mat(mat_b, n - 2)).m[0][0] - 1LL;

			cout << q_mult(q_mult(q_pow(x, z1+mod-1, mod), q_pow(y, z2, mod), mod), q_pow(a % mod, z3 % (mod - 1), mod), mod) << endl;
		}
	}
}
发布了157 篇原创文章 · 获赞 99 · 访问量 9821

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104176195