快速幂问题+中国剩余定理

poj 3233 矩阵快速幂+二分求解

题目传送门

//矩阵快速幂+二分
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=30+5;
typedef struct{
    int mar[maxn][maxn];
}MATRAX;
MATRAX a,per;                   //初始矩阵 单位矩阵
int n,m;
void init()
{
    memset(per.mar,0,sizeof(per.mar));
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            scanf("%d",&a.mar[i][j]);
            a.mar[i][j]%=m;
            if(i==j) per.mar[i][j]=1;
        }
}
//矩阵相加
MATRAX add(MATRAX a,MATRAX b)
{
    MATRAX c;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            c.mar[i][j]=(a.mar[i][j]+b.mar[i][j])%m;
    return c;
}
//矩阵相乘
MATRAX multi(MATRAX a,MATRAX b)
{
    MATRAX c;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
    {
        c.mar[i][j]=0;
        for(int k=0;k<n;k++)
        {
            c.mar[i][j]+=(a.mar[i][k]*b.mar[k][j])%m;
        }
        c.mar[i][j]%=m;
    }
    return c;
}
//矩阵快速幂
MATRAX pow_mod(int k)
{
    MATRAX p,ans=per;
    p=a;
    while(k)
    {
        if(k&1) ans=multi(ans,p);
        p=multi(p,p);
        k>>=1;
    }
    return ans;
}
MATRAX MatraxSum(int k)
{
    if(k==1) return a;
    MATRAX temp,b;
    temp=MatraxSum(k/2);
    if(k&1) {
        b=pow_mod(k/2);
        temp=add(temp,multi(temp,b));
        temp=add(temp,pow_mod(k));
    }
    else {
            b=pow_mod(k/2);
            temp=add(temp,multi(temp,b));
    }
    return temp;
}
int main()
{
    int k;
    while(scanf("%d%d%d",&n,&k,&m)==3)
    {
            init();
            MATRAX solve;
            solve=MatraxSum(k);
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    printf("%d%c",solve.mar[i][j],j+1==n?'\n':' ');
    }
    return 0;
}

poj 1995 快速幂

题目传送门

//矩阵快速幂
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
LL pow_mod(LL a,LL b,LL MOD)
{
    LL res=1;
    while(b)
    {
        if(b&1) res=res*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL M,ans=0;
        scanf("%lld",&M);
        int k;
        scanf("%d",&k);
        for(int i=0;i<k;i++)
        {
            LL a,b,x;
            scanf("%lld%lld",&a,&b);
            if(a==0) continue;
            else if(b==0) x=1;
                    else x=pow_mod(a,b,M);
            ans=(ans+x)%M;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

poj 1006 中国剩余定理      特殊的有规律的线性同余方程组

题目传送门

//中国剩余定理
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(b==0)
    {
        d=a;
        x=1;
        y=0;
        return;
    }
    else {
        ex_gcd(b,a%b,d,x,y);
        LL temp=x;
        x=y;
        y=temp-(a/b)*y;
    }
}
int main()
{
    int kase=0;
    LL p,e,i,d;
    while(scanf("%lld%lld%lld%lld",&p,&e,&i,&d)==4)
    {
        if(p==-1&&e==-1&&i==-1&&d==-1) break;
        LL ans=0,f,x,y,M=23*28*33;
        ex_gcd(28*33,23,f,x,y);
        ans=(ans+28*33*x*p)%M;
        ex_gcd(23*33,28,f,x,y);
        ans=(ans+23*33*x*e)%M;
        ex_gcd(23*28,33,f,x,y);
        ans=(ans+23*28*x*i)%M;
        ans=ans-d;
        if(ans<=0) ans+=M;
        printf("Case %d: the next triple peak occurs in %lld days.\n",++kase,ans);
    }
    return 0;
}

hdu 1788 两种解法

题目传送门

1.找到了一定的规律,发现只需要求出这些数的最小公倍数,再减a即可

//中国剩余定理
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    LL n,a;
    while(scanf("%lld%lld",&n,&a)==2)
    {
        if(n==0&&a==0) break;
        LL M=1;
        for(int i=0;i<n;i++)
        {
            LL k;
            scanf("%lld",&k);
            M=M/gcd(M,k)*k;
        }
        cout<<M-a<<endl;
    }
    return 0;
}

2.求解线性同余方程组

//求解线性同余方程组
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(b==0)
    {
        d=a;
        x=1;
        y=0;
        return;
    }
    else {
        ex_gcd(b,a%b,d,x,y);
        LL temp=x;
        x=y;
        y=temp-(a/b)*y;
    }
}
int main()
{
    LL n,a;
    while(scanf("%lld%lld",&n,&a)==2)
    {
        if(n==0&&a==0) break;
        LL r,k;
        scanf("%lld",&k);
        r=k-a;
        for(int i=0;i<n-1;i++)
        {
            LL k1,r1,d,x,y,c;
            scanf("%lld",&k1);
            r1=k1-a;
            c=r1-r;
            ex_gcd(k,k1,d,x,y);
            LL t=k1/d;
            x=(x*(c/d)%t+t)%t;
            r=k*x+r;
            k=k/d*k1;
        }
        cout<<r<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值