题意:
一个长度为正数的字符串,只包含“a"和"b"两种字符。
每次操作,把所有的b变成ab,a变成b。
如S(1) = ab, 则S(2)=b(ab) =bab
记L(n)为第n个串的长度。
给出L(n) = X , L(m) = Y, L(k)
做法:
设S(n)中字符a、b的个数分别为a(n)、b(n),则L(n)= a(n) + b(n)
很明显有 a(n+1)=b(n),b(n+1) = a(n)+b(n)
即满足斐波那契数列的性质。
于是可以通过构造转移矩阵,利用快速幂,来得到任意两项之间的关系。
不妨设n < m,假设得到的矩阵为
|a b|
|c d|
则有 a * a(n) + b * b(n) = a(m)
c * a(n) + d * b(n) = b(m)
又
a(n) + b(n) = L(n) = X
a(m) + b(m) = L(m) = Y
于是可解出a(n), b(n) ,若小于0 说明字符个数小于0,明显不合题意。
类似可算出a(1),b(1),同样必须保证大于等于0
最后再推出k的情况即可。
#include <cstdio>
#include <iostream>
using namespace std;
const int MOD = 1000000007, INF = 1e9;
typedef long long ll;
const int N = 2;
struct Mat {
ll mat[N][N];
void init() {
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
mat[i][j] = i || j ? 1 : 0;
}
void init2(int x) {
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
mat[i][j] = i == j ? x : 0;
}
Mat operator * (const Mat &ano) {
Mat res;
res.init2(0);
for(int i = 0; i < N; i++)
for(int j = 0; j < N; j++)
for(int k = 0; k < N; k++) {
res.mat[i][j] += mat[i][k] * ano.mat[k][j];
res.mat[i][j] %= MOD;
}
return res;
}
};
Mat quickPow(Mat A, int n) {
Mat res;
res.init2(1);
while(n) {
if(n & 1)
res = res * A;
A = A * A;
n >>= 1;
}
return res;
}
// a * x + b * y = s1
// c * x + d * y = s2
void fun(ll a, ll b, ll s1,
ll c, ll d, ll s2, ll &x, ll &y) {
x = y = -1;
if(b * c != d * a) {
y = (a * s2 - c * s1) / (a * d - b * c);
if(a)
x = (s1 - b * y) / a;
else if(c)
x = (s2 - d * y) / c;
if(a * x + b * y != s1 ||
c * x + d * y != s2)
x = y = -1;
}
}
int main() {
// freopen("in.txt", "r", stdin);
int t, n, x, m, y, k;
ll ans;
Mat A;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d%d%d", &n, &x, &m, &y, &k);
if(n > m) {
swap(n, m);
swap(x, y);
}
ll an, bn;
A.init();
A = quickPow(A, m - n);
fun(1, 1, x, A.mat[0][0] + A.mat[1][0],
A.mat[0][1] + A.mat[1][1], y, an, bn);
if(an < 0 || bn < 0) {
puts("Impossible");
continue;
}
ll a1, b1;
A.init();
A = quickPow(A, n-1);
fun(A.mat[0][0], A.mat[0][1], an,
A.mat[1][0], A.mat[1][1], bn,
a1, b1);
if(a1 < 0 || b1 < 0){
puts("Impossible");
continue;
}
A.init();
ll ak, bk;
if(k >= n) {
A = quickPow(A, k - n);
ak = an * ((A.mat[0][0] + A.mat[1][0]) % MOD);
bk = bn * ((A.mat[0][1] + A.mat[1][1]) % MOD);
ak %= MOD, bk %= MOD;
ans = ak + bk;
} else {
A = quickPow(A, n - k);
fun(A.mat[0][0], A.mat[0][1], an,
A.mat[1][0], A.mat[1][1], bn,
ak, bk);
if(ak < 0 || bk < 0) {
puts("Impossible");
continue;
}
ak %= MOD, bk %= MOD;
ans = ak + bk;
}
ans %= MOD;
printf("%d\n", (int)ans);
}
return 0;
}