题面在最下方。
吐个槽,矩阵我没写long long挂了40分 (事实上正常写法不用long long,但。。我。。不正常)
首先推一下简单的结果找找感觉,就可以得到一个结论:第n个阶段的病毒数An=K^(n-1)
等比数列求和会吗?Sn=S1+S2+...+Sn=1+K+K2+...+Kn-1,由于题目说的是第n阶段前有多少个病毒分裂,那么答案就是Sn-1。
但是我们发现,这个坑逼玩意儿不太好求。
为啥?如果你用求和公式的话,要写个高精度,除啊模啊,想想都头大!如果你不用高精度 ,偏要O(n)枚举求和的话,本题nmax=10^18,那就非常有意思了。
怎么搞?都想到这里了,难道还要放弃?
天无绝人之路,本题解法一就出来了:这玩意可以分治解决!
思路:设问题求的是1 + K + K2 + K3 + ⋯ + KM, 对 此式子分治解决,先求得1 + K + ⋯ + KM/2-1 , 然后KM/2 + ⋯ + KM等于前式乘以KM/2 得到,将两式合并即可,而对于前半部分,递归使用以上算法即可,完美地避开 了除法运算。分治共log(N)层,每层只递归计算一边,然后合并调用快速幂,所 以总的复杂度为 O(log2(N))。
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 #define LL long long 5 LL N, K, P; 6 7 LL ksm(LL x, LL k) { 8 LL res = 1; 9 for (; k>0; x=x*x%P, k>>=1) 10 if (k&1) res = res*x%P; 11 return res; 12 } 13 14 LL sum(LL n) { 15 if (!n) return 0; 16 LL res = sum(n>>1); 17 LL res1 = (res + res * ksm(K, n>>1)) % P; 18 if (n & 1) return (res1 + ksm(K, n-1)) % P; 19 else return res1; 20 } 21 22 int main() 23 { 24 freopen("split.in", "r", stdin); 25 freopen("split.out", "w", stdout); 26 cin >> K >> N >> P; 27 K %= P; 28 cout << sum(N - 1) << '\n'; 29 return 0; 30 }
解法二:矩阵快速幂
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 template<class T> inline void read(T &_a){ 5 int _ch=getchar();_a=0; 6 while(_ch<'0' || _ch>'9')_ch=getchar(); 7 while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();} 8 } 9 10 long long k,n,p; 11 12 struct matrix 13 { 14 long long a[2][2]; 15 matrix() {memset(a,0,sizeof(a));} 16 matrix operator * (matrix &x) const { 17 matrix res; 18 for (register int i=0;i<=1;++i) 19 for (register int v=0;v<=1;++v) 20 for (register int j=0;j<=1;++j) 21 res.a[i][v]+=a[i][j]*x.a[j][v],res.a[i][v]%=p; 22 return res; 23 } 24 }; 25 26 matrix clac(matrix a,long long b) 27 { 28 matrix res; 29 res.a[0][0]=res.a[1][1]=1; 30 while(b) 31 { 32 if(b&1) res=res*a; 33 b>>=1; 34 a=a*a; 35 } 36 return res; 37 } 38 39 int main() 40 { 41 read(k); read(n); read(p); 42 matrix op; 43 op.a[0][0]=k; op.a[1][0]=op.a[1][1]=1; 44 op=clac(op,n-2); 45 long long ans=op.a[1][0]*k%p; 46 ans+=op.a[1][1]; 47 printf("%lld",ans%p); 48 return 0; 49 }