[关闭]
@comzyh 2013-12-24T03:21:08.000000Z 字数 1584 阅读 2306

等比数列求和的二分法

常见问题:给定整数M,等比数列an
求其前n项和对M的模
朴素的想法,我们可以用等比数列求和公式Sn=a1(1qn)1q求得和再模除M,但是计算过程中取模导致分母下面的1-q不能直接除,要求1-q的乘法逆元;
这里介绍另一种思路,就是使用二分的思想,很像矩阵快速幂 首先,我们先讨论一个简单的问题:
a1+a2+a3+a4+a5+a6+a7+a8的和
提取公因式,我们能把原式变为
(a1+a2+a3+a4)(1+a4)
进一步变换为
(a1+a2)(1+a2)(1+a4)
=a(a+a1)(1+a2)(1+a4)
我们把这种等比数列前2k项和记为S(k)有递推式S(k)=S(k1)(1+a2k1)
这是二分法的关键,也就是说我们能在log(n)的时间内求出等比数列前2k项的和
我们要求的不是前2的整数次幂的时候我们将n分解为2的整次幂的和;
比如求前等比数列11项的和,我们将11(二进制表示1011)分解为1+2+8(二进制1+10+1000) 前11项的和可以表示为:
(a1)+(a2+a3)+(a4+a5+a6+a7+a8+a9+a10+a11)
可进一步表示为
a0(a1)+a1(a1+a2)+a3(a1+a2+a3+a4+a5+a6+a7+a8)
即:a0S(0)+a1S(1)+a3S(3)
Well done!我们又把原式分解成了多个axS(y)的和 在这里可能可能会有一个小小的疑问,就是axS(y)中的x和y是怎么确定的,这里我是参考的矩阵快速幂的思想,x就是已经处理的指数的和,y根据当前处理的比特位置决定
一个快速幂大概这么写

  1. int pow(int a,int b)
  2. {
  3. int ans=1,power=a;
  4. while (b)
  5. {
  6. if (b&1)
  7. ans*=power;
  8. power*=power;
  9. b>>=1;
  10. }
  11. return ans;
  12. }

注意,这里面的power一直充当a2k的角色,在等比数列求和中,他担任的功能还包括提供S(k)=S(k1)(1+a2k1)中的2k1 下面是完整的样例程序:

  1. //等比数列求和
  2. //author:comzyh
  3. //等比数列求和
  4. #include <cstdio>
  5. const int MOD=9901;
  6. int A,B;
  7. int sum(int n,long long k)
  8. {
  9. n%=MOD;
  10. int ans=0;
  11. int power=n;
  12. int powersum=n;//S(y)
  13. int mul=1;//a^x
  14. while (k)
  15. {
  16. if (k&1)
  17. {
  18. ans+=mul*powersum; ans%=MOD;
  19. mul*=power; mul%=MOD;
  20. }
  21. powersum*=(power+1); powersum%=MOD;
  22. power*=power; power%=MOD;
  23. k>>=1;
  24. }
  25. return ans;
  26. }
  27. int main()
  28. {
  29. int n,k;
  30. while (scanf("%d%d",&n,&k)!=EOF)
  31. {
  32. printf("%d\n",sum(n,k));
  33. }
  34. return 0;
  35. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注