【问题描述】
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
【来源】
重庆八中命题。
【思路梳理】
题不难,模拟考试时非常紧张就WA掉了。大致思路还是比较清晰:一个二分快速幂,再来一个二分求幂和两个分治算法。设d[i]=在第i个周期前(注意是在第i个周期以前,即还没有进行第i次分裂)病毒分裂的次数。因为第一个周期有且仅有一个病毒,所以显然d[2]=1=k^0,d[3]=k=k^1,d[4]=k*k=k^2,etc,不难发现对于我们所求的结果sum[n]有:
sum[n]=d[2]+d[3]+…+d[n-2]
=k^0+k^1+k^2+…+k^n-2。
公式出来了就不难实现了。每一次进行求和时进行二分:
所求的部分的和S = a^1 + a^2 + … + a^n
设前半部分的和Lhalf = a^1 + a^2 + … + a^(n/2)
显然后半部分的和Rhalf=a^(n/2+1)+a^(n/2+2)+ … + a^(n)
=Lhalf×a^(p/2)则当n为偶数时: S=Lhalf + a^(n/2)*Lhalf
则当n为奇数时: S=Lhalf + a^(n/2)*Lhaf + a^n
因为幂次可能很大,所以使用二分快速幂不再赘述,直接给出Cpp代码。
【Cpp代码】
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,k,m,ans=0;
long long mod(long long x)
{
return x%m;
}
long long qkpower(long long x,long long p)//二分快速幂
{
if(p==0) return 1;
long long t=mod(qkpower(x,p/2));
long long cnt=mod(t*t);
if(p%2) cnt=mod(cnt*x);
return cnt;
}
//ans=1+(k^1+k^2+...+k^n-2)
long long solve(long long x,long long p)//solve每一次计算的是从k开始的和
{
if(p==0) return 0;
long long t=solve(x,p/2);
long long cnt=mod(t+t*qkpower(x,p/2));
if(p%2) cnt=mod(cnt+qkpower(x,p));
return mod(cnt);
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
cin>>k>>n>>m;
ans=solve(k,n-2);
cout<<mod(ans+1);//k^0实际上是没有加到的
return 0;
}