高精度、快速幂与快速排序

目录

高精度介绍

一、高精度加

二、高精度减

三、高精度乘

1.高精乘单精

2.高精乘高精

四、高精度除

快速幂介绍

一、快速幂取模

快速排序介绍

一、快速排序

综合


高精度介绍

高精度算法主要用于处理大型数据,其基本原理是通过数组来存储数据,通过对其数组元素进行操作来实现整体的加减乘除。

一、高精度加

只需要开辟一个数组来存储,即  c[i]=a[i]+b[i]+x,  x为低位的进位,然后  x=c[i]/10;  c[i]%=10;即可。

#include <bits/stdc++.h>
using namespace std;
string n,m;
int a[520],b[520],c[520];
int main() {
   cin>>a>>b;
    int la=n.size(),lb=m.size();
    for(int i=1;i<=la;i++)a[i]=n[la-i]-48;    //倒置 
    for(int i=1;i<=lb;i++)b[i]=m[lb-i]-48;
      
    int x=0,lc=1;                             //x为进位 
    while(la>=lc||lb>=lc)
    {
	c[lc]+=at[lc]+bt[lc]+x;
	x=c[lc]/10;
	c[lc]%=10;
	lc++;
	}
	c[lc]=x;                     //最后一个进位补上
	if(c[lc]==0)                 //可能没有进位 
	lc--;
	  
	for(int i=lc;i>=1;i--)
	cout<<c[i];
	  
}

P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

二、高精度减

类似加法,但有补位的情况,还需注意负数结果。

#include<bits/stdc++.h>
using namespace std;
int a[101000],b[101000],c[101000];
char n1[101000],n2[101000],t[101000];
int la, lb, lc,flag=0;
int main() {
    cin >> n1 >> n2;
    la=strlen(n1),lb=strlen(n2);

    if(lb>la||strcmp(n1,n2)<0&&la==lb)        //若n2大于n1,则交换字符串
    {
 	flag=1;
 	strcpy(t,n1);
 	strcpy(n1,n2);
 	strcpy(n2,t);
 	la=strlen(n1);
 	lb=strlen(n2);
    }
    
    for(int i=0; i<la; i++) a[la - i] =n1[i]-48;
    for(int i=0; i<lb; i++) b[lb - i] =n2[i]-48;
    lc = 1;
    while(lc<=la||lc<=lb) 
   {
        if(a[lc] < b[lc])              //不足补零
		{
            c[lc] = a[lc] + 10 - b[lc];
            a[lc+1]--;
        }
        else
            c[lc] = a[lc] - b[lc]; 
        lc++;
    }

    while(c[lc] == 0 && lc > 1)      //清除前导零
         lc--;
         if(flag)
         cout<<'-';
    for(int i=lc; i>=1; i--)cout << c[i];
 
    return 0;
}

P2142 高精度减法 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

三、高精度乘

1.高精乘单精

将单精乘以高精度的每一位,注意最高位进位可能不止进一位。


#include<iostream>
#include <bits/stdc++.h>
#include<algorithm>
using namespace std;
int s[10000];
int n;
int t,ans=0,num;
int main() {
	cin >> t;
	while(t--)
	{
		cin>>n;
		s[1]=1;
     	int	p=1,jw=0,j;    //p代表位数,jw代表进位 
		for(int i=2;i<=n;i++)
		{

		   for(j=1;j<=p;j++)  
		   {
		   s[j]=s[j]*i+jw;
		   jw=s[j]/10;
		   s[j]%=10;
		   }
           
           while(jw>0)   //若还有进位,则处理进位 
		   {
		   	s[j]=jw%10;
		   	jw/=10;
		   	j++;
		   }
		   p=j-1;    //位数等于j-1 
		   
		}
		
	}

}

P1591 阶乘数码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

2.高精乘高精

高精乘高精套用公式  c[i+j-1]=c[i+j-1]+a[i]*b[j]+x  (x为进位),i+lb位是最高位进位,积长度最长为两因子长度相加。


#include<iostream>
#include <bits/stdc++.h>
#include<algorithm>
using namespace std;
string at,bt;
int a[2005],b[2005],c[4000005];

int main() {
   cin>>at>>bt;
   int la=at.size(),lb=bt.size();
   for(int i=1;i<=la;i++)a[i]=at[la-i]-48;
   for(int i=1;i<=lb;i++)b[i]=bt[lb-i]-48;
      int x=0,lc=1;
    
    for(int i=1;i<=la;i++)
    {
		x=0;
		for(int j=1;j<=lb;j++)
		{
			c[i+j-1]=c[i+j-1]+x+a[i]*b[j];
			x=c[i+j-1]/10;
			c[i+j-1]%=10;
			
		}
		c[i+lb]=x;
	}

	lc=la+lb;
	while(c[lc]==0&&lc>1)
	lc--;
	  for(int i=lc;i>=1;i--)
	  cout<<c[i];
	  return 0;
}

P1303 A*B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

四、高精度除

将被除数的每一位加上上一位的余数(余数需要乘10)除以除数,即   c[i]=(a[i]+x*10)/b   ,高精除单精不需要倒序。

#include<bits/stdc++.h>
using namespace std;
int t;
int n;
char s[5005];
int a[5005],b,c[5005];
int main() {

    cin>>s>>b;
    int la=strlen(s);
    for(int i=1;i<=la;i++)
    a[i]=s[i-1]-48;             //高精除单精不用倒序 
    
    long long x=0;                   //余数 
    for(int i=1;i<=la;i++)
    {
		c[i]=(a[i]+x*10)/b;    
		x=(a[i]+x*10)%b;   
	}
	
	int lc=1;
	while(c[lc]==0&&lc<la)    //清除前置零 
	lc++;
	for(int i=lc;i<=la;i++)
	cout<<c[i];
}

P1480 A/B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

快速幂介绍

快速幂算法可以快速的算出指数非常大的幂,比单独一个for循环指数 O(n)要快的多,其基本原理如下:

3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3)

3^10=9*9*9*9*9=81*81*9=6561*9

每次指数除以2,底数取平方,每次循环的次数都会减半。

一、快速幂取模

此题题目为幂取位数,即取模。  乘法取模公式为  (a*b)%p=(a%p*b%p)%p    

#include <iostream>
using namespace std;
long long  a,b,p;
int main()
{
	cin>>a>>b>>p;
	long long  ans=1,mul=a,index=b;
	while(index>0)
	{
		if(index&1)     //若指数为奇数的话,得先把树枝乘上
		{
			ans*=mul;
			ans%=p;
		}
		index>>=1;
		mul=(mul*mul)%p;     //底数取平方
	}
	ans%=p;
    cout<<a<<'^'<<b<<" mod "<<p<<'='<<ans;
}

P1226 【模板】快速幂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

快速排序介绍

快速排序的原理是选定一个分界值,将数组中小于分界值的数放在它的右边,大于它的放在左边,再把数组中分界位置分为两个数组,重复上列操作。

一、快速排序

模板。

#include<bits/stdc++.h>
#include <algorithm>
using namespace std;
int n,m;
int a[2000000];
void quicksort(int l,int r)
{
	int i=l,j=r,t=a[l];
	if(i>=j)
	return ;
	
	while(i<j)
	{
		while(a[j]>=t&&i<j)j--;
		while(a[i]<=t&&i<j)i++;
		swap(a[i],a[j]);
	}
	swap(a[l],a[j]);
	quicksort(l,i-1);
	quicksort(i+1,r);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	std::cin>>a[i];
	quicksort(1,m);
	for(int i=1;i<=m;i++)
	cout<<a[i]<<' ';
}

P1271 【深基9.例1】选举学生会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

综合

此题为快速幂+高精乘,还需知道2^p的位数为  p*log10(2)+1  

#include<bits/stdc++.h>
#include<cmath>
using namespace std;
typedef long long ll;
int a[1000000],b[1000000],c[1000000];  //a是主因子,b是副因子,c辅助存储 
int p,inde,la=1,lb=1;
void multiply1()
{
	memset(c,0,sizeof c);
	for(int i=1;i<=la;i++)
	{
		int x=0;
		for(int j=1;j<=lb;j++)
		{
			c[i+j-1]+=a[i]*b[j]+x;
			x=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
		c[i+lb]=x;
	}
	int lc=la+lb;
	while(c[lc]==0&&lc>1)
	lc--;
	
	for(int i=1;i<=lc;i++)
	a[i]=c[i];
	la=min(500,lc);
}

void multiply2()
{
	memset(c,0,sizeof c);
	for(int i=1;i<=lb;i++)
	{
		int x=0;
		for(int j=1;j<=lb;j++)
		{
			c[i+j-1]+=b[i]*b[j]+x;
			x=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
		c[i+lb]=x;
	}
	int lc=lb+lb;
	while(c[lc]==0&&lc>1)
	lc--;
	
	for(int i=1;i<=lc;i++)
	b[i]=c[i];
	lb=min(lc,500);
}

void quickM()     //快速幂 
{
	while(inde>0)
	{
		if(inde&1)
		{
			multiply1();   //高精乘 
		}
		inde>>=1;
		multiply2();
	}
}
int main()
{
    cin>>p;
    inde=p;
    cout<<(int)(p*log10(2)+1);    //2^p位数等于10^X=X+1,log10(2^p)=X
	                                    //故X+1等于 log10(2^p)+1
    a[1]=1,b[1]=2;
    quickM();
    a[1]--;
    for(int i=500,j=0;i>=1;i--)
    {
		if(j%50==0)
		cout<<endl;
		cout<<a[i];
		j++;
	}
    	
}

P1045 [NOIP2003 普及组] 麦森数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值