【問題描述】
A學校的實驗室新研製出了一種十分厲害的病毒。由於這種病毒太難以人工製造了,所以專家們在一開始只做出了一個這樣的病毒。
這個病毒被植入了特殊的微型芯片,使其可以具有一些可編程的特殊性能。最重要的一個性能就是,專家們可以自行設定病毒的分裂能力 K,假如現在有x 個病毒,下一個分裂週期將會有 Kx個一模一樣的病毒。你作爲該實驗室的數據分析員,需要統計出在分裂到第N個週期前,一共有多少個病毒單體進行了分裂。一開始時總是隻有一個病毒,這個局面算作第一個週期。由於答案可能很大,專家們只需要你告訴他們對給定的P取模後的答案。
【輸入格式】
一行三個整數,依次是K, N, P。
【輸出格式】
一行一個整數,你的答案(對P取模) 。
【輸入樣例】
【樣例1】
5 3 7
【樣例2】
2 6 23
【輸出樣例】
【樣例1】
6
【樣例2】
8
【樣例解釋】
樣例一解釋:第一個週期有 1 個病毒,產生了一次分裂。第二個週期有 1*5=5 個病毒, 這五個病毒都會分裂。 所以第三個週期前一共進行了1+5等於 6 次分裂。 答案即爲6 mod 7 = 6。
【數據範圍】
1 < N < 10^18
1 < K , P < 2^31
這道題求的是K^0+K^1+…+K^n-2取餘,就是求冪的和,又因爲N的值很大,如果暴力求解肯定會超時。所以要用快速冪優化,但是用快速冪也會超時,這裏就用分治二分+快速冪,數據全過沒問題。最好數據類型全部用long long,省心。
#include<stdio.h>
#include<math.h>
using namespace std;
long long k,n,p;
//二分+快速冪求和
long long qkpow(long long k,long long n)
{
long long ans=1,t=k;
while(n>0)
{
if(n&1) ans=(ans*t)%p;
n>>=1;
t=(t*t)%p;
}
return ans;
}
long long solve(long long k,long long n) //二分求和
{
if(n==1) return k;
long long t1=solve(k,n>>1);
long long t2=qkpow(k,n>>1);
if(n&1) return (t1+(t1*t2)%p+qkpow(k,n))%p; //奇
else return (t1+(t1*t2)%p)%p; //偶
}
int main()
{
freopen("virus.in","r",stdin);
freopen("virus.out","w",stdout);
scanf("%I64d %I64d %I64d",&k,&n,&p);
long long ans=(solve(k,n-2)+1)%p;
printf("%I64d",ans);
return 0;
}