51nod - 1573 分解 - 矩阵快速幂

51nod 算法马拉松17(告别奥运)B 分解 51nod 算法马拉松17(告别奥运)B 分解
题意 :给出一个 n ,问(1+2)n 能否拆成 m+m1 的形式,如果能,输出 m ,否则输出 no。

想法
观察(1+2)n,它总能写成 a+b2 的形式,如果 a2n=m2b2n=m1 或者 a2n=m12b2n=m ,那就可以了。 于是我们设 (1+2)n=an+bn2 ,不难找到 (anbn)=(a1b1)(1211)n1

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int mod = 1e9 + 7;
int t = 2;
struct mat
{
    long long v[maxn][maxn];
    int n;
    void clear()
    {
        n = t;
        memset(v, 0, sizeof(v));
    }
    void unit()
    {
        clear();
        for(int i=0; i<n; i++)
            v[i][i] = 1;
    }
    void fro()
    {
        clear();
        v[0][1] = v[1][0] = v[1][1] = 1;
    }
    void print()
    {
        for(int i=0; i<n; i++)
        {
            cout << v[i][0];
            for(int j=1; j<n; j++)
                cout << " " << v[i][j];
            cout << endl;
        }
    }

};
mat operator * (const mat a, const mat b)
{
    mat res;
    res.clear();
    for(int i=0; i<t; i++)
    {
        for(int j=0; j<t; j++)
        {
            for(int k=0; k<t; k++)
            {
                res.v[i][j] = (res.v[i][j] + a.v[i][k] * b.v[k][j]) % mod;
            }
        }
    }
    return res;
}
mat operator ^ (mat a, long long b)
{
    mat r , base = a;
    r.unit();
    while(b)
    {
        if(b&1)
            r = r * base;
        base = base * base;
        b >>= 1;
    }
    return r;
}
int main()
{
    long long m;
    mat a;
    a.clear();
    a.v[0][0] = 1, a.v[0][1] = 1;
    a.v[1][0] = 2, a.v[1][1] = 1;
    cin >> m;
    if(m == 0) {
        cout << 1 << endl; return 0;
    } else if(m == 1) {
        cout << 2 << endl; return 0;
    }
    a = (a^(m-1));
    long long t = a.v[0][0] + a.v[1][0];
    long long s = a.v[0][1] + a.v[1][1];
    long long tm = (t % mod) * (t % mod) % mod;
    long long sm = ((s % mod) * (s % mod) * 2 + 1 )% mod;
    long long ms = ((s % mod) * (s % mod) * 2 - 1 + mod)% mod;
    if(tm == sm)
        cout << tm << endl;
    else if(tm == ms)
        cout << (tm + 1 + mod) % mod << endl;
    else
        cout << "no" << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值