作为一个毒瘤出题人(wzy:我不是毒瘤出题人,这些题明明很水的),wzy的题干十分复杂,但是把题意简化之后,相当简单粗暴。。。
求首项为1,等比为m,项数为t的等比数列的和,答案对k取模
不保证m与k互质
如果m与k互质的话,用等比数列的求和公式在求个逆元就能解决了,但是本题显然不能,于是必须考虑不含有除法的算法
于是就有了分治求等比数列和的办法。
设s(x)为等比数列的第n项
由等比数列的性质得到s(y)=s(x)*m^(y-x) (y>x)
将一个长度为2r的等比数列拆分成登场的两部分,对应的项的比均为m^r,所以两部分和的差值也为m^r,所以只需要计算出前r项的和,就可以直接得到后r项的和。
如果数列的长度为2r+1,那么必须手动计算出第2r+1项的值,然后将后面的2r项拆分计算。
对于整个数列,递归计算,便可以在logt的时间内求出解。
#include<cstdio> void read(int &y) { y=0;char x=getchar(); while(x<'0'||x>'9') x=getchar(); while(x>='0'&&x<='9') { y=y*10+x-'0'; x=getchar(); } } int m,t,k; long long ksm(long long a,long long b) { long long s=a,re=1; while(b) { if(b&1) re=re*s%k; s=s*s%k; b>>=1; } return re%k; } long long sum(int l,int r) { if(l==r) return 1; if((r-l+1)&1) return (ksm(m,r)+sum(l,(r-1)>>1)*(ksm(m,((r-1)>>1)+1)+1))%k; else return (sum(l,r>>1)*(ksm(m,(r>>1)+1)+1))%k; } int main() { read(m);read(t);read(k); printf("%d",sum(0,t-1)); return 0; }