sdut-C - A Short problem

According to a research, VIM users tend to have shorter fingers, compared with Emacs users.
  Hence they prefer problems short, too. Here is a short one:
  Given n (1 <= n <= 10 18), You should solve for
g(g(g(n))) mod 10 9 + 7

where
g(n) = 3g(n - 1) + g(n - 2)( g(1) = 1, g(0) = 0)

Input
  There are several test cases. For each test case there is an integer n in a single line.
  Please process until EOF (End Of File).

Output
  For each test case, please print a single line with a integer, the corresponding answer to this case.
Sample Input

    0
    1
    2

Sample Output

    0
    1

ps:类似于2333矩阵,只是需要求出循环节,这个东西我不会2333, 网上找的找循环节的代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long mo1=1000000007;
long long mo2=222222224;
long long mo3=183120;
long long s1[3][3],s2[3][3],s3[3][3];
long long f(long long n,long long mo)
{
    int i,j,k;
    s1[0][0]=s2[0][0]=3;
    s1[0][1]=s2[0][1]=1;
    s1[1][0]=s2[1][0]=1;
    s1[1][1]=s2[1][1]=0;//对s[1], s[2]数组进行初始化
    n-=2;
    while (n)
    {
        {//如果n&1是1,s1=s1*s2;
            if (n&1)
            {
                memset(s3,0,sizeof(s3));
                for (k=0; k<2; k++)
                {
                    for (i=0; i<2; i++)
                    {
                        if (!s1[i][k])
                            continue;
                        for (j=0; j<2; j++)
                            s3[i][j]=(s3[i][j]+s1[i][k]*s2[k][j])%mo;
                    }
                }
                for (i=0; i<2; i++)
                    for (j=0; j<2; j++)
                        s2[i][j]=s3[i][j];//将s3的值赋给s2
            }
        }
        {//无论n&1是0还是1,s1=s1*s1;
            memset(s3,0,sizeof(s3));
            for (k=0; k<2; k++)
            {
                for (i=0; i<2; i++)
                {
                    if (!s1[i][k]) continue;
                    for (j=0; j<2; j++)
                        s3[i][j]=(s3[i][j]+s1[i][k]*s1[k][j])%mo;
                }
            }
            for (i=0; i<2; i++)
                for (j=0; j<2; j++)
                    s1[i][j]=s3[i][j];
        }
        n>>=1;
    }
    return s2[0][0];
}
int main()
{
    long long n;
    long long ans;
    while (~scanf("%lld",&n))
    {
        if (n==0)
        {
            printf("0\n");
            continue;
        }
        if (n==1)
        {
            printf("1\n");
            continue;
        }
        ans=f(n,mo3);
//        printf("%d\n", ans);
        if (ans>=2) //一定要有,不然ans<2时函数就会死循环。
            ans=f(ans,mo2);
        if (ans>=2)
            ans=f(ans,mo1);
        printf("%lld\n",ans);
    }
}
//#include<cstdio>//**找循环节**
//long long mo1=1000000007;
//int main()
//{
//    long long i=1,a=1,b=0,c;
//    for(i=1, a=1, b=0;;)
//    {
//        while (i)
//        {
//            c=(3*a+b)%mo1;
//            b=a;
//            a=c;
//            if (a==1&&b==0)
//            {
//                printf("%lld\n",i);
//                break;
//            }
//            i++;
//        }
//        mo1=i;
//    }
//}

其实关于矩阵快速幂,和快速幂是相差不多的,但是我就是搞不懂该怎么构建矩阵,曾经想强行理解一波,但是奈何理想很丰满,现实很骨感。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值