[BZOJ3240][Noi2013]矩阵游戏 && 快速幂

本文介绍了如何利用费马小定理进行快速幂运算,简化了矩阵运算的过程,并通过实例展示了从F[1][1]到F[n][1]和F[n][m]的推导过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当我知道这题矩阵可以用费马小定理搞快速幂的时候 我眼泪都要落下来了QAQ

首先求一发通项F[1][1]->F[2][1]的通项

然后写成A+B的形式

若a != 1

       A = (a^(m-1))*c

       B = b*((a^(m-1))/(a-1)) * c + d

若a == 1

       A = c

       B = B * (m-1) * c + d

那么从F[1][1]->F[n][1]可以写作

      F[n][1] = A^(n-1) + B * ( (A^(n-1) - 1) / (A-1))

然后再用F[n][1]推到F[n][m]就好啦

莫名其妙代码长好多QAQ

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
typedef long double LD;
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
	while('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x*f;
}
const int MAXN = 1000000;
const int MOD = 1000000007;
char n[MAXN+10], m[MAXN+10];
int A, B, a, b, c, d, X, Y, XX;
int lenn, lenm;
int powa[MAXN+10], powA[MAXN+10];
inline int pow_mod(int x, int k) {
	int ret = 1;
	while(k) {
		if(k & 1) ret = 1LL * ret * x % MOD;
		x = 1LL * x * x % MOD;
		k >>= 1;
	}
	return ret;
}
inline int pow_mod(char *s, int len, int *t) {
	int ret = 1;
	for(int i = 0; i < len; i++) {
		int x = len-i-1;
		for(int p = 0; p < s[i]-'0'; p++)
			ret = 1LL * ret * t[x] % MOD;
	}
	return ret;
}
inline int inv(int x) {
	return pow_mod(x, MOD-2);
}
inline int getint(char *s, int len) {
	int ans = 0;
	for(int i = 0; i < len; i++)
		ans = (1LL * ans * 10 + s[i] - '0') % MOD;
	return ans;
}
void Doit() {		
	int ans = 0;
	powA[0] = A;
	powA[1] = pow_mod(A, 10);
	for(int i = 2; i <= lenn; i++) powA[i] = pow_mod(powA[i-1], 10);
	X = 1LL * pow_mod(n, lenn, powA) * inv(A) % MOD;
	if(A != 1) 
		ans = ((X + 1LL * B * (X-1) % MOD * inv(A-1) % MOD) % MOD + MOD) % MOD;
	else 
		ans = ((1 + 1LL * B * (getint(n, lenn)-1)) % MOD + MOD) % MOD;
	if(a != 1) 
		ans = ((1LL * ans * XX % MOD + 1LL * b * (XX-1) % MOD * inv(a-1) % MOD) % MOD + MOD) % MOD;
	else 
		ans = ((ans + 1LL * b * (getint(m, lenm)-1) % MOD) + MOD) % MOD;
	PF("%d\n", ans);
}
int main() {
	SF("%s%s%d%d%d%d", n, m, &a, &b, &c, &d);
	lenn = strlen(n); lenm = strlen(m);
	powa[0] = a; powa[1] = pow_mod(a, 10);
	for(int i = 2; i <= lenm; i++) powa[i] = pow_mod(powa[i-1], 10);
	if(a != 1) {
		XX = 1LL * pow_mod(m, lenm, powa) * inv(a) % MOD;
		A = 1LL * XX * c % MOD;
		B = (1LL * b * (XX-1) % MOD * inv(a-1) % MOD * c % MOD + d) % MOD;
		Y = (XX + 1LL * b * (XX-1) % MOD * inv(a-1) % MOD) % MOD;
	}
	else {
		A = c % MOD;
		B = 1LL * b * (getint(m, lenm)-1) % MOD;
		Y = (B+1) % MOD;
		B = (1LL * B * c + d) % MOD;
		if(B < 0) B += MOD;
	}
	Doit();
}
/*
300000000001234560000000000000000000 400000002315654564897891231560000000000000000000000000 99999999 99999999 99999999 999999999
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值