2019牛客多校算法训练营 B generator 1(矩阵快速幂 + 十进制加速)

题目链接
这道题因为n的取值为10的10的六次方,所以只能用string类型的变量输入,并且要用10进制加速使复杂度上升到略比O(2log(n))大的级别。
另外要注意的是 矩阵相乘的时候做三次取余操作和做一次取余操作所耗的时间相差还是蛮大的,若是对时间限制不是那么大的题目,可以无限次mod,但是此题因为值的最大值为1e9, 相乘为1e18 (小于9e18) 不会超long long, 所以可以相乘后再取余,这样就不会超时,如果取三次余就会超时。

总结:
1.矩阵快速幂的10进制加速
2.矩阵相乘中取余操作的多少会对运行时间造成较大影响

下面附上ac代码:

#include <bits/stdc++.h>
#define mod(x) x%mo
typedef long long ll; 
using namespace std;

ll x0, x1, num_a, num_b, mo;
string n;
struct mat {
	ll m[5][5];
}unit;

void init() {
	memset(unit.m, 0, sizeof(unit.m));
	for (int i = 0; i < 2; ++i)
		unit.m[i][i] = 1;
}
mat operator * (mat a, mat b) {
	mat res;
	for (int i = 0; i < 2; ++i) {
		for (int j = 0; j < 2; ++j) {
			ll x = 0;
			for (int k = 0; k < 2; ++k) {
				x += mod( a.m[i][k] * b.m[k][j] );
				x = mod(x);
			}
			res.m[i][j] = x;
		}
	}
	return res;
}
mat power2(mat a, ll n) {
	mat res = unit;
	while (n) {
		if (n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}
mat power10(mat a, string n) {
	mat res = unit;
	for (ll i = n.size()-1; i >= 0; --i) {
		ll id = n[i] - '0';
		res = res * power2(a, id);
		a = power2(a, 10);
	}
	return res;
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	init();
	cin >> x0 >> x1 >> num_a >> num_b;
	cin >> n >> mo;
	if (n == "1") {
		cout << mod(x1) << '\n';
		return 0; 
	}
	mat a, b;
	a.m[0][0] = mod(x1); a.m[0][1] = mod(x0) ;
	b.m[0][0] = mod(num_a);  b.m[0][1] = 1;
	b.m[1][0] = mod(num_b);  b.m[1][1] = 0;
	b = power10(b, n);
	mat ans;
	for (int i = 0; i < 1; ++i) {
		for (int j = 0; j < 2; ++j) {
			ll x = 0;
			for (int k = 0; k < 2; ++k) {
				x += mod( a.m[i][k] * b.m[k][j] );
				x = mod(x);
			}
			ans.m[i][j] = x;
		}
	}
	cout << ans.m[0][1] << '\n';
	return 0;
} 
发布了51 篇原创文章 · 获赞 6 · 访问量 1666

猜你喜欢

转载自blog.csdn.net/qq_43555854/article/details/100787768