lightOJ 1052 String Growth(矩陣快速冪,找規律)

String Growth

Zibon just started his courses in Computer science. After having some lectures on programming courses he fell in love with strings. He started to play with strings and experiments on them. One day he started a string of arbitrary (of course positive) length consisting of only {a, b}. He considered it as 1st string and generated subsequent strings from it by replacing all the b’s with ab and all the a’s with b. For example, if he ith string is abab, (i+1)th string will be b(ab)b(ab) = babbab. He found that the Nth string has length X and Mth string has length Y. He wondered what will be length of the Kth string. Can you help him?

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case begins with five integers N, X, M, Y, K. (0 < N, M, X, Y, K < 109 and N ≠ M).

Output
For each case print one line containing the case number and L which is the desired length (mod 1000000007) or the string “Impossible” if it’s not possible.

Sample Input
2
3 16 5 42 6
5 1 6 10 9
Sample Output
Case 1: 68
Case 2: Impossible

題意:有一種字符串只由a和b組成,字符串每次變化,a都會變成b,b會變成ab,比如aba→babb→abbabab,現在告訴你第n次變化的字符串長度是x,第m次變化的字符串長度是y,問你第k次變化時字符串的長度。初始字符串未知。

思路:我們先隨便列幾項看看
a→b→ab→bab→abbab→bababbab→abbabbababbab→……
每一串a,b的個數如下
這裏寫圖片描述

顯而易見,a和b都呈斐波那契數列,總和自然也是斐波那契數列。雖然我們不知道字符串的初始狀態,但是我們可以根據題目給的兩個狀態去反推。
已知a和b的關係可以表示成以下矩陣遞推式
這裏寫圖片描述
根據題目給的兩個狀態,可以列出方程組這裏寫圖片描述
然後我們利用矩陣快速冪就可以找到a[n],b[n],a[m],b[m]分別對應多少倍的a[-1]+多少倍的b[-1]。(我們知道a,b的位置應該從1開始,但是這裏我們往前額外算兩位,這樣可以判斷出第一位和第二位不滿足條件的情況)然後就變成了二元一次方程組,求解出a[-1]和b[-1]後,就可以再用一次矩陣快速冪求出任意位置的字符串長度。
然後接下來就是考慮Impossible的情況。
1,我們可以先找一個使所有位置字符串長度最短的情況,那就是第一個字符串是a的情況,也就是我們上面舉的那個例子,同一位置下其它情況的字符串的長度都會比該情況要長。所以說如果第k個位置的字符串長度比這個最短的情況還要短,那就是Impossible。
2,1中的字符串長度最短的情況,在不超過題目數據範圍的情況下所能達到的位置是最遠的。因爲題目給你的數據範圍只到1e9,所以說任何情況下位置都不能超過第一種情況的最遠位置。如果不太好理解的話我舉個例子:
這裏寫圖片描述
3,如果出現了m>n而x>y的情況,很明顯是Impossible,因爲由題意可知不能出現後者比前者小的情況。
4,解方程組的時候,如果解出來a[-1]和b[-1]不是整數,或者小於0,直接Impossible。
5,在解出a[-1]和b[-1]的值之前,如果使用矩陣快速冪的過程中取了模,那也說明數據不正確,Impossible。

#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <iostream>  
#include <algorithm>  
using namespace std;
#define LL long long  
const int mod = 1e9 + 7;
struct matrix {
    LL f[2][2];
};
LL flag, mark, dp[100];
void init()
{
    LL i, j, k;
    dp[0] = 0;
    dp[1] = 1;
    for (i = 2;; i++)
    {
        dp[i] = dp[i - 1] + dp[i - 2];
        if (dp[i] >= 1e9)break;
    }
    mark = i;
}
matrix mul(matrix a, matrix b)
{
    LL i, j, k;
    matrix c;
    memset(c.f, 0, sizeof(c.f));
    for (i = 0; i<2; i++)
    {
        for (j = 0; j<2; j++)
        {
            for (k = 0; k<2; k++)
            {
                c.f[i][j] = c.f[i][j] + a.f[i][k] * b.f[k][j];
                if (c.f[i][j] >= mod || c.f[i][j] <= -mod)
                {
                    flag = 1;
                    c.f[i][j] %= mod;
                }
            }
        }
    }
    return c;
}
matrix pow_mod(matrix a, LL b)
{
    matrix s;
    s.f[0][0] = s.f[1][1] = 1;
    s.f[0][1] = s.f[1][0] = 0;
    while (b)
    {
        if (b & 1)s = mul(s, a);
        a = mul(a, a);
        b = b >> 1;
    }
    return s;
}
int main()
{
    init();

    LL T, tt = 0;
    cin >> T;
    while (T--)
    {
        LL n, m, x, y, k, i, j;
        flag = 0;
        cin >> n >> x >> m >> y >> k;
        if (n>m)
        {
            swap(n, m);
            swap(x, y);
        }
        cout << "Case " << ++tt << ": ";
        if (y<x || m >= mark || x<dp[n] || y<dp[m]) { cout << "Impossible" << endl; continue; }
        matrix e, g, gg;
        e.f[0][0] = 0; e.f[1][0] = e.f[0][1] = e.f[1][1] = 1;
        g = pow_mod(e, n - 1);
        gg = pow_mod(e, m - 1);
        LL a, b, c, d, p, q;
        a = g.f[0][0] + g.f[1][0];
        b = g.f[0][1] + g.f[1][1];
        c = gg.f[0][0] + gg.f[1][0];
        d = gg.f[0][1] + gg.f[1][1];
        if (flag || (c*x - a*y) % (b*c - a*d) || (d*x - b*y) % (a*d - b*c)) { cout << "Impossible" << endl; continue; }
        p = (d*x - b*y) / (a*d - b*c);
        q = (c*x - a*y) / (b*c - a*d);
        if (p<0 || q<0) { cout << "Impossible" << endl; continue; }
        g = pow_mod(e, k - 1);
        cout << (p*(g.f[0][0] + g.f[1][0]) + q*(g.f[0][1] + g.f[1][1])) % mod << endl;
    }
    return 0;
}
發佈了93 篇原創文章 · 獲贊 78 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章