hdu-4990-矩阵快速幂 or 等比数列+快速幂+除法取模

这个题有两种解法,一个是等比数列加快速幂,二是矩阵快速幂。

矩阵快速幂很好做,代码这里不写了:题目已知奇数项a[n]=a[n-1]*2+1,偶数项a[n]=a[n-1]*2。分别拆分可得奇数:a[n]=a[n-1]+2*a[n-2]+1,偶数项:a[n]=a[n-1]+2*a[n-2]+1。发现都是同一个式子,所以直接矩阵快速幂就可以了

等比数列就是列出前几项观察可得a[n]=2^(n-1)+2^(n-3)+2^(n-5)+....然后分奇偶得出奇数时为(2^(n+1)-1)/3,偶数时得出为(2^(n)-1)*2/3。

这个题场上做的时候没发现模m其实是变化的,所以可能存在逆元不存在的情况,所以拓展欧几里得和费马求逆元都不行,这里用的是除法取模

(a/b)%m就等于a%(b*m)/b,证明如下

(a/b)%m=c  ==>  a/b+c=k*m

==>  a+b*c=k*m*b

==>  a%(m*b)=b*c

==> a%(m*b)/b=c

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <set>

using namespace std;

typedef long long int ll;
ll n,m;

ll qp(ll a,ll b,ll mod)
{
    ll res=1;
    while(b)
    {
        if(b%2) res=(res*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return res;
}

int main()
{
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        ll ans;
        if(n%2)
        {
            ans=(qp(2,n+1,3*m)-1)%(3*m)/3;//注意整个过程都要对3*m取模
        }
        else
        {
            ans=(qp(2,n,3*m)-1)%(3*m)/3;
            ans=ans*2%m;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alusang/article/details/81224956