洛谷传送门
BZOJ传送门
题目描述
婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的 n n 行列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用 F[i][j] F [ i ] [ j ] 来表示矩阵中第 i i 行第列的元素,则 F[i][j] F [ i ] [ j ] 满足下面的递推式:
F[1][1]=1 F [ 1 ] [ 1 ] = 1
F[i,j]=a∗F[i][j−1]+b(j≠1) F [ i , j ] = a ∗ F [ i ] [ j − 1 ] + b ( j ≠ 1 )
F[i,1]=c∗F[i−1][m]+d(i≠1) F [ i , 1 ] = c ∗ F [ i − 1 ] [ m ] + d ( i ≠ 1 )
递推式中 a,b,c,d a , b , c , d 都是给定的常数。
现在婷婷想知道 F[n][m] F [ n ] [ m ] 的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出 F[n][m] F [ n ] [ m ] 除以 1,000,000,007 1 , 000 , 000 , 007 的余数。
输入输出格式
输入格式:
输入文件matrix.in包含一行有六个整数 n,m,a,b,c,d n , m , a , b , c , d 。意义如题所述。
输出格式:
输出文件matrix.out包含一个整数,表示 F[n][m] F [ n ] [ m ] 除以 1,000,000,007 1 , 000 , 000 , 007 的余数。
输入输出样例
输入样例#1:
3 4 1 3 2 6
输出样例#1:
85
说明
【样例1说明】
样例中的矩阵为:
1 4 7 10
26 29 32 35
76 79 82 85
数据范围
解题分析
听说很多人用矩阵水过了, 都是卡常dalao%%%%%%…
蒟蒻用的是推式子的方法, 总复杂度为 O(lgN) O ( l g N ) 。
我们先考虑横排的递推, 看一下这个递推式:
发现这是可以通项算第 M M 项的, 具体而言第项为:
考虑推至
F[i+1][1]
F
[
i
+
1
]
[
1
]
, 可得:
如果 a≠1 a ≠ 1 , 则设 A=c×aM−1 A = c × a M − 1 , B=b×c×aM−1a−1+d B = b × c × a M − 1 a − 1 + d ,同样运用等比数列求和求通项,则有:
F[i+1][1]=A×F[i][1]+B F [ i + 1 ] [ 1 ] = A × F [ i ] [ 1 ] + BF[N+1][1]=AN×F[i][1]+B×AN−1A−1 F [ N + 1 ] [ 1 ] = A N × F [ i ] [ 1 ] + B × A N − 1 A − 1如果 a=1 a = 1 , 则设 C=b×c×(M−1)+d C = b × c × ( M − 1 ) + d ,则有:
F[i+1][1]=c×F[i][1]+C F [ i + 1 ] [ 1 ] = c × F [ i ] [ 1 ] + CF[N+1][1]=F[i][1]+C×N (c=1) F [ N + 1 ] [ 1 ] = F [ i ] [ 1 ] + C × N ( c = 1 )F[N+1][1]=cN×F[i][1]+C×cN−1c−1 (c≠1) F [ N + 1 ] [ 1 ] = c N × F [ i ] [ 1 ] + C × c N − 1 c − 1 ( c ≠ 1 )
这样我们就求出 F[N+1][1] F [ N + 1 ] [ 1 ] 的值, 要求 F[N][M] F [ N ] [ M ] 的值减去 d d 再乘上的逆元即可。
还有一个问题, N、M N 、 M 太大了怎么办? 我们发现 1000000007 1000000007 为质数, 而对于一个数 x x , 次方总是等于1(费马小定理), 所以我们处理质数上面的 N、M N 、 M 时只需要疯狂 MOD1e9+6 M O D 1 e 9 + 6 即可。 在乘数上面的 N、M N 、 M 更简单, 直接疯狂 MOD1e9+7 M O D 1 e 9 + 7 即可。
注意运算时随时取模。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define R register
#define W while
#define gc getchar()
#define IN inline
#define MX 1000500
#define ll long long
#define MOD 1000000007ll
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
ll ind, mod, a, b, c, d;
int len;
char buf[MX];
struct INFO
{ll ind, mod;} N, M;//ind为指数上的结果, mod为乘数上的结果
IN ll fpow(ll base, ll tim)
{
ll ret = 1;
for (R unsigned i = 0; i <= 31; ++i, base = base * base % MOD)
if((1 << i) & tim) ret = ret * base % MOD;
return ret;
}
IN void get(char *dat, INFO &x)
{
for (R int i = 1; i <= len; ++i)
{
x.ind = (x.ind * 10 + dat[i] - 48) % (MOD - 1);
x.mod = (x.mod * 10 + dat[i] - 48) % MOD;
}
}
IN ll inv(ll val) {return fpow(val, MOD - 2);}
int main(void)
{
scanf("%s", buf + 1); len = std::strlen(buf + 1); get(buf, N);
scanf("%s", buf + 1); len = std::strlen(buf + 1); get(buf, M);
in(a), in(b), in(c), in(d);
ll A, B, C, ans;
if(a == 1)
{
C = (c * b % MOD * (M.mod - 1) % MOD + d) % MOD;
if(c == 1) ans = (1 + N.mod * C % MOD) % MOD;
else
{
ll pw = fpow(c, N.ind);
ans = (pw + C * (pw - 1 + MOD) % MOD * inv(c - 1)) % MOD;
}
}
else
{
ll pw1 = fpow(a, (M.ind - 1 + MOD) % MOD);
A = pw1 * c % MOD;
B = (b * c % MOD * (pw1 + MOD - 1) % MOD * inv(a - 1) % MOD + d) % MOD;
ll pw2 = fpow(A, N.ind);
ans = pw2 + B * (pw2 + MOD - 1) % MOD * inv(A - 1) % MOD;
}
ans = (ans - d + MOD) % MOD * inv(c);
printf("%lld", (ans % MOD + MOD) % MOD);
}