LightOJ1052 String Growth[矩阵快速幂]

题意:

一串字符串,它只有 a 和 b 组成,假设第 i 个字符串是 abab 那么第 i+1个字符串则为 b(ab)b(ab) 即下一个字符串,是由上一个字符串,通过将 a 变为 b,将 b 变为 ab,得到的。给你第 N 个字符串的跟第 M 个字符串的长度,求出第 K 个字符串的长度,其中,给定的字符串长度会有可能不符合要求,那时请输出Impossible。


题解:

我们假设第 i 个的字符串 a 的个数为 x,b 的个数为 y。

第 i 个 总和为    根据题目给的条件,我们可以推出下一个

第 i+1 个    总和为 

第 i+2 个  总和为

第 i+3 个 总和为 

第 i+4 个  总和为      以此类推...

我们看总和的系数  x 的系数是  1 1 2 3 5    y 的系数是 1 2 3 5 8

这显然是非常常见的斐波拉契数列

我们把设定 n < m (如果大于交换一下就好)

打个表,我们可以知道斐波拉契的第46项已经是大于 1e9 的了,而题目给定的长度是个真实长度,并非取模之后的。

那么意味着 n,m 的差值肯定是小于45 (先不说 n,m 是小于45) ,意味着,如果两者如果差值超过了 45 那么必然给定的长度,是错误的。

斐波拉契的起始值 fib[0]=0,fib[1]=1,fib[2]=1。

我们设 第 n 个字符串的 a,b 个数分别为 x,y,x 的系数为 fib[1],y 的系数为 fib[2]

那么第 m 个字符串的 a,b 个数分别为 fib[m-n+1]*x,fib[m-n+2]*y  x的系数为fib[m-n+1]  y 的系数为fib[m-n+2]


可以用矩阵快速幂或者直接暴力求出第 m 个字符串的 a,b 系数,因为数据差值非常小,所以暴力完全可行。

 之后我们就可以得到这两条式子。

那么解方程,就可以算出 第 n 个字符串的 a,b 个数,先判断是否可行,即 如果存在 a 或 b 的个数小于0,那么就是Impossible

然而得到这个还不够,首先我们必须先判断了第 n 个字符串是否符合从第 1 个字符串开始变换出来的,即如果出现样例②那样的,第 5 个字符串的长度为 1,这显然是怎么都不可能从第 1 个字符串变出来的。


① n>=45

根据我们上述说过的,第46项斐波拉契数已经是超过了1e9,所以这种情况是Impossible。


② n==1

判断 a 的个数加上 b 的个数是否大于等于0,如果是,那么就直接可以从第 1 项通过算出第 k 项的斐波拉契系数,直接得到答案。否则 Impossible 。


③ n>1 && n<45

因为我们在跟 m 的判断是否符合当中,已经求出了第 n 个字符串的 a,b 个数,那么我们只要知道从第一项开始到第 n 项的 a,b的单独个数的系数。

我们通过刚才上面的公式可以发现 实际上是可以转换成

 不需要管 n 具体代指什么, 我们只是表达出他们的关系。

我们可以发现,只要我们求出 b 的系数即可  因为 f[n-2] = f[n] - f[n-1]。

我们可以发现,第 i 个字符串的 b 的个数的式子里面,y 的系数应该是 fib[i] (从第 1 个字符串开始算起,并且斐波拉契数列从0作为第一项)。 同样用矩阵快速幂求出该系数。

 之后会得到这样两条式子,继续解方程。(分别代指第 n 个字符串的 a 的个数和 b 的个数,x,y 分别代指第 1 个字符串的 a 的个数和 b 的个数)

求出第 1 个字符串的 a,b 的个数,我们可以直接根据这个来求出第 k 个字符串的长度(这次就要一定使用矩阵快速幂了,因为 k 的范围很大)。



#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=3;
ll aa[N][N],bb[N][N],ans[N][N],tmp[N][N];
void initial()
{
    aa[0][0]=0;
    aa[0][1]=aa[1][0]=aa[1][1]=1;
    memset(ans,0,sizeof(ans));
    for (int i=0 ; i<N ; ++i)
        ans[i][i]=1;
}
void Pow(ll a[][N],ll b[][N],int n)
{
    memset(tmp,0,sizeof(tmp));
    for (int i=0 ; i<n ; ++i)
        for (int j=0 ; j<n ; ++j)
            for (int k=0 ; k<n ; ++k)
                    tmp[i][k]=(tmp[i][k]+a[i][j]*b[j][k]%mod)%mod;
    for (int i=0 ; i<n ; ++i)
        for (int j=0 ; j<n ; ++j)
            a[i][j]=tmp[i][j];
}
void Pow(ll a[][N],ll m)
{
    while (m)
    {
        if (m&1)
            Pow(ans,a,2);
        Pow(a,a,2);
        m>>=1;
    }
}
void getans(ll x,ll y,int p)
{
    initial();
    Pow(aa,p-1);
    ll k1=(ans[0][0]+ans[0][1])%mod;
    ll k2=(ans[1][0]+ans[1][1])%mod;
    ll ans=(x*k1%mod+y*k2%mod)%mod;
    printf("%lld\n",ans);
}
bool check(int x1,int y1,int n,int p)
{
    if (n>=45)
        return 0;
    if (n==1)
    {
        if (x1+y1<=0)
            return 0;
        getans(x1,y1,p);
        return 1;
    }
    initial();
    Pow(aa,n-2);
    ll k1=ans[0][0]+ans[0][1];
    ll k2=ans[1][0]+ans[1][1];
    ll x=(y1*k1-x1*k2)/(k1*k1-(k2*k2-k1*k2));
    ll y=(y1-k1*x)/k2;
    if (x<0 || y<0)
        return 0;
    getans(x,y,p);
    return 1;
}
int main()
{
    int T;
    scanf("%d",&T);
    for (int test=1 ; test<=T ; ++test)
    {
        int n,m,x,y,k;
        scanf("%d%d%d%d%d",&n,&x,&m,&y,&k);
        if (n>m)
        {
            swap(n,m);
            swap(x,y);
        }
        printf("Case %d: ",test);
        if (m-n<45)
        {
            ll a=1,b=1,c;
            for (int i=0 ; i<m-n ; ++i)
            {
                c=a+b;
                a=b;
                b=c;
            }
            ll x1=b*x-y;
            ll y1;
            if (!(x1%(b-a)))
            {
                x1=x1/(b-a);
                y1=x-x1;
                if (x1<0 || y1<0 || !check(x1,y1,n,k))
                    printf("Impossible\n");
            }
            else
                printf("Impossible\n");
        }
        else
            printf("Impossible\n");
    }
    return 0;
}



阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ControlBear/article/details/77763229
文章标签: LightOJ 矩阵快速幂
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭