1615: 劉備闖三國之三顧茅廬(三)
Time Limit: 1000 MS Memory Limit: 128 MBSubmit: 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
5 123456789
94 265
Sample Output
16317634
39
HINT
Source
題目鏈接:
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;
}
/*
//
//
*/