您的位置:首页 > 其它

数学知识积累

2014-03-04 21:34 204 查看

快速求幂算法

参见了别人的博客http://blog.sina.com.cn/s/blog_3f2fa9610100soxb.html,了解到了快速求幂的一种方法,比简单的循环相乘要大大减少乘法次数,自己学习后写的c++代码如下

bigint power(bigint x, int n)
{
bigint ret;
ret.set(1);
while (n!=0)
{
if (n&1==1)
ret=ret*x;
x=x*x;
n>>=1;
}
return ret;
}
这里用到了位运算,同时提高了运算效率。bigint数据类型是我自己定义的,可忽略。
接着上一步继续深入,当我们需要对一个很大的乘幂结果取模时,由于a*b%m=(a%m)*(b%m)的原理,可以将取模过程融入到快速求幂过程中,将代码稍加改进即可:

bigint power(bigint x, int n, int k)
{
bigint ret;
ret.set(1);
while (n!=0)
{
if (n&1==1)
ret=(ret*x)%k;
x=(x*x)%k;
n>>=1;
}
return ret;
}


同样这也是从大神的博客学来的http://blog.sina.com.cn/s/blog_8619a25801010wcy.html。看来要想学好计算机,一定要好好学数学,这是读研的重要任务之一。

矩阵乘法在数列递归中的运用

今天做清华的一道数列递归题,如果用递归算法实现起来十分容易,可是显然这道题不是考递归算法,含有的大数据一定会超时。我想了很久也找不到解决方法,上网看才知道有一种我从来没见过的算法,即矩阵乘法在数列递归中的运用。一个典型的例子就是斐波那契数列的非递归算法,具体参考这里 http://blog.sina.com.cn/s/blog_6ea2c6a20100x359.html 。运用矩阵的二分乘,可以大大降低复杂度,达到O(log
n),二分乘就是上面讲到的快速求幂法。二阶方阵的乘法代码如下:

matrix mul(matrix &x, matrix &y)
{
matrix ret;
ret.a[0][0]=(x.a[0][0]*y.a[0][0]+x.a[0][1]*y.a[1][0])%MOD;
ret.a[0][1]=(x.a[0][0]*y.a[0][1]+x.a[0][1]*y.a[1][1])%MOD;
ret.a[1][0]=(x.a[1][0]*y.a[1][1]+x.a[0][0]*y.a[1][0])%MOD;
ret.a[1][1]=(x.a[1][0]*y.a[0][1]+x.a[1][1]*y.a[1][1])%MOD;
return ret;
}


素数筛法

之前已经写过相关代码,可是遇到同样的题还是错了。主要原因是当时没有理解为什么要用素数筛。现在学习到,判断质数的暴力法时间复杂度为O(n),而素数筛可以将其降为O(sqrt(n)),原因是当搜索到sqrt(n)后,还没找到能整除n的整数,那么n为质数,假设存在x>sqrt(n),能整除n,那么一定有y=n/x<sqrt(n),能整除n,那么在搜索到sqrt(n)之前就可以判断n不是质数了。同样,在找整数n的质因数时,从2开始依次用质数整除,当除到sqrt(n)商还不为0时,那么这个商本身就是一个质数,在原来的质因数数量上+1即可。素数筛法的初始化代码如下:

void init()
{
for (int i=0;i<MAX;++i)
mark[i]=true;
mark[0]=mark[1]=false;
size=0;
for (int i=2;i<MAX;++i)
{
if (mark[i]==true)
{
prime[size++]=i;
for (int j=2;i*j<MAX;++j)
mark[i*j]=false;
}
}
}


位运算

与运算&可用于二进制取位操作,例如想取x的末尾,直接x&1,取倒数第二位,则x&2,以此类推,要去一个二进制数的倒数第n为,则将该数和2^(n-1)相与,若为0则该位为0,否则该位为1。

移位操作可以快速得到2^n的数,如要得到2^5,只需要将1左移5位,即1<<5。

或操作可以将目标二进制位强制转化为1。

在使用位运算的时候要注意运算优先级的问题,由于优先级较低,最好加括号,避免不必要的错误~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: