HDU 4291 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 <= 1018), 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


题解:

假如最外层要求模10^9+7,则令L0=10^9+7

将最外层内部看做一个整体x,则x在L0下可以求出一个循环节L1

那么x的值对L1取模不影响结果

将次外层内部看做一个整体y,则y在L1下可以求出一个循环节L2

那么y的值对L2取模不影响结果

......


求循环节的代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

#define lint __int64
const lint mod = 1000000007;
lint L1 = 222222224, L2 = 183120, L3;

void test()
{
    printf("start\n");
    lint gn, gn1 = 1, gn2 = 0;
/*
    for(lint i = 2; ; i++)
    {
        gn = (3 * gn1 + gn2) % mod;
        if(gn == 1 && gn1 == 0)
        {
            printf("循环节L1:%I64d\n", i - 1);
            L1 = i - 1; //222222224
            break;
        }
        gn2 = gn1;
        gn1 = gn;
    }

    gn = 3, gn1 = 1, gn2 = 0;
    for(lint i = 2; ; i++)
    {
        gn = (3 * gn1 + gn2) % L1;
        if(gn == 1 && gn1 == 0)
        {
            printf("循环节L2:%I64d\n", i - 1);
            L2 = i - 1; //183120
            break;
        }
        gn2 = gn1;
        gn1 = gn;
    }
*/
    gn = 3, gn1 = 1, gn2 = 0;
    for(lint i = 2; ; i++)
    {
        gn = (3 * gn1 + gn2) % L2;
        if(gn == 1 && gn1 == 0)
        {
            printf("循环节L3:%I64d\n", i - 1);
            L3 = i - 1; //183120
            break;
        }
        gn2 = gn1;
        gn1 = gn;
    }

    printf("over\n");
}

int main()
{
    test();
}

题解:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

#define MAXN 3
#define lint __int64
const lint L0 = 1000000007;
const lint L1 = 222222224;
const lint L2  = 183120;
const lint L3 = 240;
lint gn, mod;

class CMatrix
{
public:
    lint a[MAXN][MAXN], n;
    void init(int n, int flag);
    CMatrix operator+(CMatrix);
    CMatrix operator*(CMatrix);
    CMatrix power(lint);
};

void CMatrix::init(int n, int flag)
{
    this->n = n;
    memset(this->a, 0, sizeof(this->a));
    if(flag == 0) return;
    for(int i = 0; i < n; i++)
        this->a[i][i] = 1;
}

CMatrix CMatrix::operator+(CMatrix tt)
{
    CMatrix ret = *this;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            ret.a[i][j] = (ret.a[i][j] + tt.a[i][j]) % mod;
    return ret;
}

CMatrix CMatrix::operator*(CMatrix tt)
{
    CMatrix ret;
    ret.init(this->n, 0);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            for(int k = 0; k < n; k++)
                ret.a[i][j] += this->a[i][k] * tt.a[k][j];
            ret.a[i][j] %= mod;
        }
    }
    return ret;
}


CMatrix CMatrix::power(lint e)
{
    CMatrix ret, tmp;
    ret.init(this->n, 1);
    tmp = *this;
    while(e > 0)
    {
        if(e & 1)
            ret = ret * tmp;
        e >>= 1;
        tmp = tmp * tmp;
    }
    return ret;
}

int main()
{
    while(scanf("%I64d", &gn) != EOF)
    {

        CMatrix x, y;
        x.n = 2;
        x.a[0][0] = 3; x.a[0][1] = 1;
        x.a[1][0] = 1; x.a[1][1] = 0;

        mod = L2;
        y = x.power(gn % L3);
        mod = L1;
        y = x.power(y.a[1][0] % L2);
        mod = L0;
        y = x.power(y.a[1][0] % L1);
        printf("%I64d\n", y.a[1][0]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值