被迫营业(
题意:(我直接CV)
描述 婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式: 输入 一行有六个整数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 |
题解:
先不考虑大数的问题:
对于矩阵中的一个数x从Fi,1不断右移到Fi,m:
设改转移为
对于矩阵中一个数x从Fi,m往下移动到Fi+1,m:
同理可以求出F1,m进行n次下移操作:
中的e和f
因此最终答案为
接下来考虑大数:
费马小定理:
所以在取模p的前提下,所以我们在使用快速幂运算时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;
}