XMU 1615 刘备闯三国之三顾茅庐(三) 【欧拉函数+快速幂+欧拉定理】

37 篇文章 1 订阅
28 篇文章 0 订阅

1615: 刘备闯三国之三顾茅庐(三)

Time Limit: 1000 MS   Memory Limit: 128 MB
Submit: 45   Solved: 8
[ Submit][ Status][ Web Board]

Description

        刘备(161年-223年6月10日),字玄德,东汉末年幽州涿郡涿县,西汉中山靖王刘胜的后代。刘备一生极具传奇色彩,早年颠沛流离、备尝艰辛最终却凭借自己的谋略终成一方霸主。那么在那个风云激荡的年代,刘备又是如何从一个卖草鞋的小人物一步一步成为蜀汉的开国皇帝呢?让我们一起拨开历史的迷雾,还原一个真实的刘备。

       公元207年冬至,当时驻军新野的刘备在徐庶的建议下,到南阳卧龙岗拜访诸葛亮。这是刘备第三次拜访诸葛亮的故事。据三国演义记载,此次刘备终于拜访到了诸葛亮,诸葛亮献上草庐对策,为诸葛亮描述了一个良好的战略远景。然而据我翻阅古籍发现:诸葛亮本人其实精通数论,他终于发现前面的题目太简单了,于是给刘备甩下了这么一道题,这是他最新的研究成果:

        题目意思很简单:

        已知:f(1)=1; f(k)=k^f(k-1),求f(n)%m。

        刘备为人深谋远虑,但对此类问题只能急得干瞪眼,请出诸葛亮事关大业,所以聪明的你自告奋勇,抄起纸笔开始计算了。

Input

 有多组数据,需处理到文件结束(EOF):

每组数据包含两个整数n,m(1<=n,m<=10^9)

Output

对于每一组数据:

       输出一个整数,f(n)%m的值

Sample Input

2 42
5 123456789
94 265

Sample Output

2
16317634
39

HINT

Source

[ Submit][ Status][ Web Board]



题目链接:

  http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1615

题目大意:

  f(1)=1; f(k)=k^f(k-1),求f(n)%m。

题目思路:

  【欧拉函数+快速幂+欧拉定理】

  定理:a^b mod c = a^(b%phi[c]+phi[c]) mod c,其中要满足b >= phi[c]。(phi为欧拉函数)

  由题目可以知道这题f(n)=n^(n-1)^(n-2)^...^2^1。由于是指数级的,f(5)就已经超出longlong范围。所以试用上面的定理优化。

  由于指数只有在4^3^2^1或更小的情况下才有可能<phi[c],所以特殊处理这四个值,其余可以递归求解。

  需要log求解欧拉函数,log求快速幂,递归调用求解函数直至取模的数=1或指数下降到可以直接求的范围。



/****************************************************
     
    Author : Coolxxx
    Copyright 2017 by Coolxxx. All rights reserved.
    BLOG : http://blog.csdn.net/u010568270
     
****************************************************/
#include<bits/stdc++.h>
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define mem(a,b) memset(a,b,sizeof(a))
const double EPS=1e-8;
const int J=10;
const int MOD=100000007;
const int MAX=0x7f7f7f7f;
const double PI=3.14159265358979323;
const int N=1004;
const int M=1004;
using namespace std;
typedef long long LL;
double anss;
LL aans;
int cas,cass;
LL n,m,lll,ans;
LL euler(LL x)
{
    LL res=x;
    int i;
    for(i=2;1LL*i*i<=x;i++)
    {
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)x/=i;
        }
    }
    if(x>1)res=res/x*(x-1);
    return res;
}
LL mi(LL x,LL y,LL mod)
{
    LL s=1;
    while(y)
    {
        if(y&1)s=(s*x)%mod;
        y/=2;
        x=(x*x)%mod;
    }
    return s;
}
LL cal(LL a,LL c)
{
    LL e=euler(c);
    if(a==3 && e>9)return 9%c;
    if(a==2 && e>2)return 2%c;
    if(a==1)return 1;
    if(c==1)return 0;
    LL b=cal(a-1,e);
    return (1LL*mi(a,b,c)*mi(a,e,c))%c;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("1.txt","r",stdin);
//  freopen("2.txt","w",stdout);
    #endif
    int i,j,k;
    int x,y,z;
//  for(scanf("%d",&cass);cass;cass--)
//  for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
//  while(~scanf("%s",s))
    while(~scanf("%lld",&n))
    {
        scanf("%lld",&m);
        printf("%lld\n",cal(n,m));
    }
    return 0;
}
/*
//
 
//
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值