矩阵快速幂

通常我们使用的快速幂是以二为底的,这次就遇到了一道以10为底的快速幂题目;

先说下快速幂

long long power(long long a,long long b)///a是底数,b是次幂
{
	long long ans=1;
	for(;b!=0;b>>=1)
	{
		if(b&1) ans=(long long)ans*a%mod;
		a=(long long)a*a%mod;
	}
	return ans;
}

在log时间内跑出a的b次幂

还有欧拉降幂   a^b%mod=a^(b%phi(mod))%mod,phi就是mod的欧拉返回值,也就是1——mod中有多少个与mod互质的数

long long phi(long long n)   ///求欧拉函数值 返回值为多少个与n互质的数
{
    long long ans=n,temp=n;
    for(int i=2;i*i<=temp;i++)
    {
        if(temp%i==0)
        {
            ans-=ans/i;
            while(temp%i== 0) temp/=i;
        }
    }
    if(temp>1) ans-=ans/temp;
    return ans;
}

还有逆元  比如/2  就是*0.5 但是不能用double会有误差尤其是在mod的情况下,所有就有了逆元

a在mod下的逆元为:power(a,phi(mod)-1);

 

上面都是与常数为例的,接下来就是矩阵形式的,这个引例就是斐波那契数列,你要求1e8以内的跑个递推循环,但是更大呢?

于是就有了矩阵快速幂  1 1   *    fn          =   fn+1

                                      1  0   *   fn-1             fn

所以只要求那个矩阵的n-1次幂就可以了   于是就可以使用矩阵快速幂(以二为底)就是把b换成矩阵,保留矩阵答案就好,和快速幂本质上一毛一样

这次呢!碰到了一个以10为底的矩阵快速幂,因为他给的数有1e6位,本来想着是欧拉降幂,但是矩阵不可以使用欧拉降幂

于是就...

先说下题目吧   给个x0,x1   给个a  ,b   xn=a*xn-1+b*xn-2  再给个n求xn%mod为多少

十进制下的矩阵快速幂板子

#include<bits/stdc++.h>
using namespace std;
long long mod;
long long x0,x1,a,b;
string n;
long long power()
{
    long long ans[3][3],k[3][3],h[3][3],h2[3][3];
    ans[1][1]=k[1][1]=a;ans[1][2]=k[1][2]=b;ans[2][1]=k[2][1]=1;ans[2][2]=k[2][2]=0;
    for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) h[i][j]=h2[i][j]=k[i][j];
    for(int ii=n.size()-1;ii>=0;ii--)
    {
        int ddd=n[ii]-'0';
        if(ddd)
        {
            for(int kkk=0;kkk<ddd;kkk++)
            {
            for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) h2[i][j]=ans[i][j];
            ans[1][1]=h2[1][1]*k[1][1]+h2[1][2]*k[2][1];
            ans[1][2]=h2[1][1]*k[1][2]+h2[1][2]*k[2][2];
            ans[2][1]=h2[2][1]*k[1][1]+h2[2][2]*k[2][1];
            ans[2][2]=h2[2][1]*k[1][2]+h2[2][2]*k[2][2];
            for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) ans[i][j]%=mod;
            }
            //for(int i=1;i<=2;i++){for(int j=1;j<=2;j++)cout<<ans[i][j]<<' ';cout<<endl;}
        }
        for (int i = 1; i < 10; i++)
        {
        for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) h2[i][j]=k[i][j];
        k[1][1]=h2[1][1]*h[1][1]+h2[1][2]*h[2][1];
        k[1][2]=h2[1][1]*h[1][2]+h2[1][2]*h[2][2];
        k[2][1]=h2[2][1]*h[1][1]+h2[2][2]*h[2][1];
        k[2][2]=h2[2][1]*h[1][2]+h2[2][2]*h[2][2];
        for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) k[i][j]%=mod;
        }
        for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) h[i][j]=k[i][j];
    }
    return ((ans[1][1]*x1)%mod+(ans[1][2]*x0)%mod)%mod;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>x0>>x1>>a>>b;
    cin>>n>>mod;
    if (n.size() == 1 && n[0] == '1')
    {
        cout<<x1<<endl;
        return 0;
    }
    for(int i=n.size()-1;i>=0;i--)
    {
        if(n[i]!='0')
        {
            n[i]=n[i]-1;
            for(int j=i+1;j<n.size();j++)
                n[j]='9';
            break;
        }
    }
    for(int i=n.size()-1;i>=0;i--)
    {
        if(n[i]!='0')
        {
            n[i]=n[i]-1;
            for(int j=i+1;j<n.size();j++)
                n[j]='9';
            break;
        }
    }
    cout<<power()<<endl;
}

神奇的ios压缩时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值