您的位置:首页 > 其它

高精度之关于高精度的其他问题

2017-05-31 20:09 239 查看

一.高精度阶乘

高精度阶乘其实就是加法的进阶版,朴素的版本可以模拟阶乘过程,首先阶乘的数据必定不会太大,所以可以持续用高精度乘以低精度进行计算。

但是问题是当n!稍微大一点就会导致运行超时。所以可以把n!拆成n*(n-1),(n-2)*(n-3)或是更少的组进行计算,最后再采用高精度乘以高精度合并结果。

二.万进制高精度

当给出的数据位数很大时带来的问题是数组可能必须开到很大并且相应的效率也会降低,所以我们希望让数组的一个位置存储更多的位数,并且考虑到数组中元素大小的限制,一个位置存四位数是最理想的,这也就是我们说的万进制高精度。当然对于普通的高精度加法和减法,存储的位数可以相应扩大。代码实现起来和普通高精度差不多,只是在取出元素时多取出几位,并且进位改变一下就可以实现。

当然我个人认为对于NOIP竞赛来说普通的高精度就足够了,所以我没有再去实现代码。

三.高精度幂

考到算我输

首先要介绍一下普通的快速幂算法,其实是利用了反复平方加速的技术。

例如当N=5时,我们可以

(1)a*a=a^2

(2)a^2*a^2=a^4

(3)a^4*a=a*5

这样只要成三次就可以了,对应的当N增大时,省下的时间会更多。

实际编程可以采用降幂的方法,即a^N=(a^2)^N/2.代码片段如下,

其中函数plus(x,y,z)表示将x*y的值赋值给ans,ans为最终的结果。

ans=1;
while(N>1)
{
if(N&1 == 1)//如果为奇数
plus(ans,a,ans);//将多出来的一个a乘到ans
plus(a,a,a);//算出来的a^2的值给a
N=N>>1;//N=N/2 ,如果a变成了a^2,那么只需要再乘N/2个a就行了
}
plus(ans,a,ans);//还有因为N是奇数乘过来的数


对应的转换为高精度问题时只需将plus改为高精度,并将a和ans的存储方式改为数组。这个时候会有一个问题影响到程序的效率,就是当计算ans乘以a的值时,我们可能会将计算的值存到一个临时数组里,计算完后再把临时数组里的数存回ans,这必然会拉低速度,所以我们其实可以全程采用一个指针指向实际的ans数组,每次计算结束后,交换指针地址。注意别忘了每次把“临时数组”腾空。

但是对于指针真的把握不好,所以建议开一个二维数组,然后持续滚动第一维。

还有就是,开始的时候我以为下面这段的思想也是快速幂:

inline long long add(int a,int N)
{
if(N<1) return 1;
int up=1;
if( N%2 )
{
up=a;
}
return (add(a,N/2)*add(a,N/2)*up)%k;//重复计算add(a,N/2)
}


但是后来才发现,快速幂是将通过将a的值扩大做到对计算进行降幂,这样原来需要乘很多次a但是我只是对a的值扩大了一次就可以少乘很多次,这样就节省了时间。而上面的这段代码实质上是一个拆分问题的过程,它只是把问题拆开,分开算,而没有进行任何的优化,所以时间复杂度和普通幂运算是一样的。

四.总
9f72

这些问题都是建立在普通高精度之上的,所以对于基础的问题一定要掌握。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  高精度算法