TZOJ4954: 矩阵游戏

被迫营业(

题意:(我直接CV)

描述

婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:
F[1][1]=1
F[i,j]=a*F[i][j-1]+b (j!=1)
F[i,1]=c*F[i-1][m]+d (i!=1)
递推式中a,b,c,d都是给定的常数。
现在婷婷想知道F[n][m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F[n][m]除以1,000,000,007的余数。

输入

一行有六个整数n,m,a,b,c,d。意义如题所述。

1<=N,M<=10^1000 000,a<=a,b,c,d<=10^9

输出

包含一个整数,表示F[n][m]除以1,000,000,007的余数

样例输入

3 4 1 3 2 6

样例输出

85

提示

样例中的矩阵为:

1 4 7 10
26 29 32 35
76 79 82 85

题解:

先不考虑大数的问题:

对于矩阵中的一个数x从Fi,1不断右移到Fi,m:

F_{i,m}=...a(a(ax+b)+b)+b...=a^{m-1}x+b*(a^{m-2}+a^{m-3}+...+a_{0})

设改转移为F_{i,m}=t*F_{i,1}+tb

对于矩阵中一个数x从Fi,m往下移动到Fi+1,m:

F_{i+1,m}=ta*(c*F_{i,m}+d)+tb

同理可以求出F1,m进行n次下移操作:

F_{n,m}=e*F{1,m}+f中的e和f

因此最终答案为  F_{n,m}=e * (ta * F_{1,1} + tb) + f

接下来考虑大数:

费马小定理:a^{p-1}\equiv 1(mod \, p)

所以在取模p的前提下a^{n}=a^{n\%(p-1))},所以我们在使用快速幂运算时n=n%(p-1)。正好我们的ta由快速幂求得,tb由等比数列求和公式时也将使用幂运算,所以题目中的n,m都可以取模mod-1

特别的,当a==1时,我们不能使用等比数列求和公式,而是直接sum=a1*n,此时的n不能为取模mod-1意义下的n而必须改用取模mod。

#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e6 + 10, MOD = 1e9 + 7, INF = 0x3f3f3f3f;
char ch[N];
LL mod(LL x)//取模MOD
{
	return (x % MOD + MOD) % MOD;
}
void get_num(LL& n1, LL& n2)//给大数取模
{
	scanf("%s", ch + 1);
	int n = strlen(ch + 1);
	for (int i = 1; i <= n; ++i)
	{
		n1 = (n1 * 10 + ch[i] - '0') % (MOD - 1);
		n2 = (n2 * 10 + ch[i] - '0') % MOD;
	}
	n1 = (n1 - 1 + MOD - 1) % (MOD - 1);
	n2 = (n2 - 1 + MOD) % MOD;
}
LL qpow(LL x, LL y)//快速幂
{
	x %= MOD;
	if (y == 0)return 1;
	if (y % 2)
		return qpow(x * x, y / 2) * x % MOD;
	return qpow(x * x, y / 2) % MOD;
}
LL inv(LL x)//求逆元
{
	return qpow(x, MOD - 2);
}

LL get_sum(LL q,LL n)//等比数列求和
{
	if (q == 1)return n;
	return mod(qpow(q, n) - 1) * inv(q - 1) % MOD;
}
void solve()
{
	LL n1 = 0, n2 = 0, m1 = 0, m2 = 0;
	get_num(n1, n2); get_num(m1, m2);
	LL a, b, c, d;
	scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
	//Fi,1转移到Fi,m
	LL ta = qpow(a, m1), tb = b * get_sum(a, a != 1 ? m1 : m2) % MOD;
	//Fi,m转移到Fi+1,m
	LL tc = c * ta % MOD, td = (d * ta + tb) % MOD;
	//F1,m转移到Fn,m
	LL e = qpow(tc, n1), f = td * get_sum(tc, tc != 1 ? n1 : n2) % MOD;
	printf("%lld\n", (e * (ta + tb) + f) % MOD);
}
int main()
{
	int T = 1;
	//scanf("%d", &T);
	while (T--)
	{
		solve();
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值