欧拉降幂

公式:
a b = { a b % φ ( p ) g c d ( a , p ) = 1 a b g c d ( a , p ) ≠ 1 , b < φ ( p )     ( m o d   p ) a b % φ ( p ) + φ ( p ) g c d ( a , p ) ≠ 1 , b ≥ φ ( p ) a^b= \begin{cases} a^{b\% \varphi(p)} & gcd(a,p)=1\\ a^b & gcd(a,p) \neq 1,b<\varphi(p) \ \ \ (mod\ p) \\ a^{b\% \varphi(p)+\varphi(p)}& gcd(a,p)\neq1,b\geq\varphi(p) \end{cases} ab=ab%φ(p)abab%φ(p)+φ(p)gcd(a,p)=1gcd(a,p)=1,b<φ(p)   (mod p)gcd(a,p)=1,bφ(p)
在这里插入图片描述
更具体
在这里插入图片描述
有关题目
hdu2837
模板题:

#include <cstdio>//欧拉降幂
#include <cstring>
using namespace std;
typedef long long ll;
ll euler(ll x)
{
    ll res=x;
    for(ll i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            res-=(res/i);
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)
        res-=(res/x);
    return res;
}
ll f_pow(ll a,ll b,ll mod)
{
    ll res=1;
    while(b)
    {
        if(b&1)
        {
            res=res*a;
            if(res>=mod)//!
                res=res%mod+mod;
        }
        a=a*a;
        if(a>=mod)//!
            a=a%mod+mod;
        b>>=1;
    }
    return res;
}
ll dfs(ll a,ll b)
{
    if(a==0)
        return 1;
    ll tmp=euler(b);
    return f_pow(a%10,dfs(a/10,tmp),b);
}
int main()
{
    int t;
    ll n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",dfs(n,m)%m);
    }
    return 0;
}

fzu 1759
模板

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll a,c;
char mi[N];
ll euler(ll x)
{
    ll res=x;
    for(ll i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            res-=(res/i);//res写成了x,wa了好几次
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)
        res-=(res/x);
    return res;
}
ll e_pow(ll x,ll y)
{
    ll res=1;
    while(y)
    {
        if(y&1)
            res=res*x%c;
        x=x*x%c;
        y>>=1;
    }
    return res%c;
}
int main()
{
    while(scanf("%I64d",&a)!=EOF)
    {
        memset(mi,'\0',sizeof(mi));
        scanf("%s",mi);//printf("b=%s\n",mi);
        scanf("%I64d",&c);
        ll ec=euler(c);//printf("ec=%I64d\n",ec);
        int len=strlen(mi);
        ll tmp=0,tt=0;
        int f=0;
        for(int i=0;i<len;i++)
        {
            tt=tt*10+(mi[i]-'0');
            if(tt>=ec)
            {
                f=1;
                break;
            }
        }
        if(f)
        {
            for(int i=0;i<len;i++)
            {
                tmp=tmp*10+(mi[i]-'0');
                tmp%=ec;
            }
            tmp+=ec;
        }
        else
            tmp=tt;
        printf("%I64d\n",e_pow(a,tmp));
    }
    return 0;
}

hdu3221
主要是能够发现规律,根据题目可知次数有递推式f(n)=f(n-1)*f(n-2)。(一开始没发现),然后列举几项,就会发现对于每一个n,其答案里面的a,b的指数是按斐波那契数列的规则增长,因此可以用矩阵来计算,然后利用欧拉降幂。就能解决。
又一次因为矩阵相乘的地方超出int错了。
代码写的不太好。

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll n,p,a,b;
int ep,f;
struct matrix
{
    ll mat[3][3];
    void clc()
    {
        for(int i=1;i<=2;i++)
            for(int j=1;j<=2;j++)
                this->mat[i][j]=0;
    }
    matrix operator *(const matrix &b)const
    {
        matrix res;
        res.clc();
        for(int i=1;i<=2;i++)
        {
            for(int k=1;k<=2;k++)
            {
                if(this->mat[i][k])
                {
                    for(int j=1;j<=2;j++)
                    {
                        if(f)
                            res.mat[i][j]=(res.mat[i][j]+(this->mat[i][k]*b.mat[k][j])%ep)%ep;
                        else
                           res.mat[i][j]=(res.mat[i][j]+this->mat[i][k]*b.mat[k][j]);
                    }
                }
                if((this->mat[1][1])>=ep)
                    f=1;
            }
        }
        return res;
    }
};
ll euler(ll x)
{
    ll res=x;
    for(ll i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            res-=(res/i);
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)
        res-=(res/x);
    return res;
}
matrix m_pow(matrix x,ll y)
{
    matrix res;
    res.clc();
    for(int i=1;i<=2;i++)
        res.mat[i][i]=1;
    while(y)
    {
        if(y&1)
            res=res*x;
        x=x*x;
        y>>=1;
    }
    return res;
}
ll f_pow(ll x,ll y)
{
    ll res=1;
    while(y)
    {
        if(y&1)
            res=res*x%p;
        x=x*x%p;
        y>>=1;
    }
    return res%p;
}
void solve()
{
    matrix A;
    A.clc();
    A.mat[1][1]=1;
    A.mat[1][2]=1;
    A.mat[2][1]=1;
    ll ans=1,u;
    matrix tmp;
    f=0;
    if(n>=2)
    {
        tmp=m_pow(A,n-2);
        u=tmp.mat[1][1];//printf("b:u=%lld\n",u);
        if(f)
            u=u%ep+ep;
    }
    else
        u=0;
    ans=f_pow(b,u);
    f=0;
    if(n>=3)
    {
        tmp=m_pow(A,n-3);
        u=tmp.mat[1][1];
        if(f)
            u=u%ep+ep;
    }
    else
    {
        if(n==1)
            u=1;
        if(n==2)
            u=0;
    }//printf("a:u=%lld\n",u);
    ans=(ans*f_pow(a,u))%p;
    printf("%lld\n",ans);
}
int main()
{
    int t,cas=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld",&a,&b,&p,&n);
        ep=euler(p);
        printf("Case #%d: ",++cas);
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值