hdu 2837 Calculation【欧拉函数,快速幂求指数循环节】

欢迎关注__Xiong的博客: http://blog.csdn.net/acmore_xiong?viewmode=list

Calculation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1912    Accepted Submission(s): 413
链接:click me

Problem Description
Assume that f(0) = 1 and 0^0=1. f(n) = (n%10)^f(n/10) for all n bigger than zero. Please calculate f(n)%m. (2 ≤ n , m ≤ 10^9, x^y means the y th power of x).
 
Input
The first line contains a single positive integer T. which is the number of test cases. T lines follows.Each case consists of one line containing two positive integers n and m.
 
Output
One integer indicating the value of f(n)%m.
 
Sample Input
      
      
2 24 20 25 20
 
Sample Output
      
      
16 5
 

题意:

已知f(0) = 1,0^0 =1,【注意,0的其他任意次方为0,虽然题没有直接给出~】,还已知f(n) = (n%10)^f(n/10),让你求f(n)%m. (2 ≤ n , m ≤ 10^9)

分析:

求解一个递归式,f(n)递归下去是需要多次求幂的,这样,我们就可以用指数循环节来降幂处理,公式如下图,phi(i)表示的i的欧拉函数值,其实指数循环节就是欧拉函数+快速幂的一个结合而已,在这个题里面需要特别注意的就是对0的处理,求0的多次方需要进行判断一下。


还有一种降幂的方法在我另外一篇博客上有详细的讲解,请参考《2015 CSUST校赛 - 超级快速幂【费马小定理】+【快速幂取模】》,追根溯源,其实费小马定理就是欧拉定理的一个拓展~,更多数论知识,请参考《数论基础的补充讲解~

实现代码:

#include <set>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define CASE(T)         for(scanf("%d",&T);T--;)
typedef __int64 LL;
int T;
LL N, M, P;
LL phi(LL n)
{
    LL ans = n;
    for(LL i = 2; i * i <= n; i++)
    {
        if(n % i == 0)
        {
            ans -= ans / i ;
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) ans -= ans / n ;
    return ans;
}
//迭代形式
//LL pow_mod(LL a, LL p, LL mod)
//{
//    LL ans = 1;
//    if(a == 0)  return p == 0;
//    while(p)
//    {
//        if(p & 1)
//        {
//            ans = ans * a % mod;
//            if(ans == 0) ans = mod;
//        }
//        a = a * a % mod;
//        p >>= 1;
//    }
//    return ans;
//}
LL pow_mod(LL a, LL b, LL MOD)
{
    if(b == 0) return 1;
    if(a == 0) return 0;
    LL x, ans;
    x = pow_mod(a, b >> 1, MOD);
    ans = x * x % MOD;
    if(b & 1) ans = (a * ans) % MOD;
    if(ans == 0) ans = MOD;
    return ans;
}
LL f(int n,int m)
{
    if(n < 10) return n;
    int x = f(n / 10,phi(m)),ans;
    ans = pow_mod(n % 10,x,m);
    return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    CASE(T)
    {
        scanf("%I64d %I64d", &N, &M);
        LL ans = f(N,M);
        printf("%I64d\n", ans % M);
    }
    return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值