高精度(vector)

由于本人当时写下此文时对于STL的用法还不太熟练,现在看来,下文中的自定义的change函数完全可以被替换为reverse函数。

比起用字符串和数组进行高精度, v e c t o r vector vector显得更加的灵活

需要注意的是,高精加法和乘法适合逆序处理,高精除法适合顺序处理,具体情况具体分析

高精之间的运算

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+10;
char as[maxn],bs[maxn];
vector<int>a,b;
int alen,blen;
inline vector<int> change(vector<int>x)//顺序转倒序
{
	vector<int>y;
	int len=(int)x.size();
	for(register int i=len-1;i>=0;i--)
		y.push_back(x[i]);
	return y;
}
inline int cmp(vector<int>x,vector<int>y)//比较 x<y return -1 x==y return 0 x>y return 1
{
	int xlen=(int)x.size(),ylen=(int)y.size();
	if(xlen<ylen)
		return -1;
	if(xlen>ylen)
		return 1;
	for(register int i=0;i<xlen;i++)
	{
		if(x[i]<y[i])
			return -1;
		if(x[i]>y[i])
			return 1;
	}
	return 0;
}
inline void out(vector<int>x)//输出
{
	int len=(int)x.size();
	for(register int i=0;i<len;i++)
		putchar(x[i]+48);
	puts("");
}
inline vector<int> plu(vector<int>x,vector<int>y)//高精+高精
{
	x=change(x);
	y=change(y);
	int xlen=(int)x.size(),ylen=(int)y.size(),zlen=max(xlen,ylen)+1;
	vector<int>z(zlen);
	for(register int i=0;i<zlen;i++)
	{
		if(i<xlen)
			z[i]+=x[i];
		if(i<ylen)
			z[i]+=y[i];
		if(z[i]>9)
		{
			z[i+1]++;
			z[i]-=10;
		}
	}
	while(zlen>1 && !z.back())
	{
		zlen--;
		z.pop_back();
	}
	return change(z);
}
inline vector<int> minu(vector<int>x,vector<int>y)//高精-高精(x>y)
{
	x=change(x);
	y=change(y);
	int xlen=(int)x.size(),ylen=(int)y.size(),zlen=max(xlen,ylen);
	vector<int>z(zlen);
	for(register int i=0;i<zlen;i++)
	{
		z[i]+=x[i];
		if(i<ylen)
			z[i]-=y[i];
		if(z[i]<0)
		{
			z[i]+=10;
			z[i+1]--;
		}
	}
	while(zlen>1 && !z.back())
	{
		zlen--;
		z.pop_back();
	}
	return change(z);
}
inline void outminu(vector<int>x,vector<int>y)//高精-高精
{
	int k=cmp(x,y);
	if(!k)
	{
		puts("0");
		return;
	}
	if(k<0)
	{
		putchar('-');
		swap(x,y);
	}
	out(minu(x,y));
}
inline vector<int> mult(vector<int>x,vector<int>y)//高精*高精
{
	int xlen=(int)x.size(),ylen=(int)y.size(),zlen=xlen+ylen;
	vector<int>z(zlen);
	x=change(x);
	y=change(y);
	for(register int i=0;i<xlen;i++)
		for(register int j=0;j<ylen;j++)
			z[i+j]+=x[i]*y[j];
	for(register int i=0;i<zlen;i++)
		if(z[i]>9)
		{
			z[i+1]+=z[i]/10;
			z[i]%=10;
		}
	while(zlen>1 && !z.back())
	{
		z.pop_back();
		zlen--;
	}
	return change(z);
}
inline vector<int> smult(vector<int>x,int y)//高精*低精
{
	x=change(x);
	int xlen=(int)x.size();
	for(register int i=0;i<xlen;i++)
		x[i]*=y;
	for(register int i=0;i<xlen-1;i++)
		if(x[i]>9)
		{
			x[i+1]+=x[i]/10;
			x[i]%=10;
		}
	while(x[xlen-1]>9)
	{
		x.push_back(x[xlen-1]/10);
		x[xlen-1]%=10;
		xlen++;
	}
	while(xlen>1 && !x.back())
	{
		x.pop_back();
		xlen--;
	}
	return change(x);
}
inline void divide(vector<int>x,vector<int>y)//高精/%高精 用压位+二分加快了一点
{
	int xlen=(int)x.size();
	bool flag=0;
	vector<int>div,mod;
	for(register int i=0;i<xlen;i++)
	{
		mod.push_back(x[i]);
		if((flag || cmp(mod,y)>=0) && i%7==0)
		{
			int d=0,l=0,r=10000000;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(cmp(mod,smult(y,mid))>=0)
				{
					if(mid>d)
						d=mid;
					l=mid+1;
				}
				else
					r=mid-1;
			}
			mod=minu(mod,smult(y,d));
			if(!mod[0])
				mod.pop_back();
			if(flag)
				for(register int i=1000000;i;i/=10)
				{
					div.push_back(d/i);
					d%=i;
				}
			else
			{
				int len=1,c=d;
				while(c)
				{
					c/=10;
					len*=10;
				}
				for(register int i=len/10;i;i/=10)
				{
					div.push_back(d/i);
					d%=i;
				}
			}
			flag=1;
		}
	}
	int d=0,l=0,r=10000000;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(cmp(mod,smult(y,mid))>=0)
		{
			if(mid>d)
				d=mid;
			l=mid+1;
		}
		else
			r=mid-1;
	}
	mod=minu(mod,smult(y,d));
	if(!mod[0])
		mod.pop_back();
	int len=1,c=d;
	while(c)
	{
		c/=10;
		len*=10;
	}
	for(register int i=len/10;i;i/=10)
	{
		div.push_back(d/i);
		d%=i;
	}
	if(div.empty())
		div.push_back(0);
	out(div);
	if(mod.empty())
		mod.push_back(0);
	out(mod);
}//在本地卡满3s的程序交洛谷竟然只有1.8s,我可能需要一台新电脑
signed main()
{
	scanf("%s%s",as+1,bs+1);
	alen=strlen(as+1);
	blen=strlen(bs+1);
	for(register int i=1;i<=alen;i++)
		a.push_back(as[i]-48);
	for(register int i=1;i<=blen;i++)
		b.push_back(bs[i]-48);
	out(plu(a,b));
	outminu(a,b);
	out(mult(a,b));
	divide(a,b);
	return 0;
}

高精/低精

#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
vector<int>a;
char s[maxn];
int len,b;
inline vector<int> divide(vector<int>x,int y)
{
	int len=(int)x.size(),sum=0;
	bool flag=0;
	vector<int>div;
	for(register int i=0;i<len;i++)
	{
		sum=(sum<<3)+(sum<<1)+x[i];
		if(flag || sum>=y)
		{
			flag=1;
			div.push_back(sum/y);
			sum%=y;
		}
	}
	if(div.empty())
		div.push_back(0);
	return div;
}
inline void out(vector<int>x)
{
	int len=(int)x.size();
	for(register int i=0;i<len;i++)
		putchar(x[i]+48);
}
int main()
{
	scanf("%s%d",s+1,&b);
	len=strlen(s+1);
	for(register int i=1;i<=len;i++)
		a.push_back(s[i]-48);
	out(divide(a,b));
    return 0;
}

高精度进制转换

#include<vector>
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
vector<int>x,ans;
int a,b,t;
string s;
inline vector<int> divide(vector<int>a,int b,int c)
{
	vector<int>d;
	d.clear();
	int len=a.size(),x=0;
	for(register int i=0;i<len;i++)
	{
		x=x*b+a[i];
		if(x>=c || !d.empty())
			d.push_back(x/c);
		x%=c;
	}
	if(d.empty())
		d.push_back(0);
	return d;
}
int main()
{
	scanf("%d",&t);
	for(register int cas=1;cas<=t;cas++)
	{
		x.clear();
		ans.clear();
		scanf("%d%d",&a,&b);
		cin>>s;
		printf("%d ",a);
		cout<<s<<endl;
		printf("%d ",b);
		int len=s.length();
		for(register int i=0;i<len;i++)
			x.push_back(s[i]-48-7*(s[i]>='A')-6*(s[i]>='a'));
		while(x.size()>1 || x.size()==1 && x[0]!=0)
		{
			len=x.size();
			int sum=0;
			for(register int i=0;i<len;i++)
				sum=(sum*a%b+x[i]%b)%b;
			ans.push_back(sum);
			x=divide(x,a,b);
		}
		if(ans.empty())
			ans.push_back(0);
		for(register int i=ans.size()-1;i>=0;i--)
			putchar(ans[i]+48+7*(ans[i]>9)+6*(ans[i]>35));
		puts("\n");
	}
	return 0;
}

在高精过程中,我们有时会因为位数过多而导致TLE,这时我们就需要压位

关于压位:令 b a s e base base为压的位数, n n n为最大位数,若有高精 × \times ×高精,则 n b a s e × 1 0 2 b a s e \frac{n}{base}\times10^{2base} basen×102base不能超过 l i m lim lim

高精度GCD

a , b a,b a,b中有 2 2 2个为偶数, a n s = 2 gcd ⁡ ( a 2 , b 2 ) ans=2\gcd(\frac{a}{2},\frac{b}{2}) ans=2gcd(2a,2b)

a , b a,b a,b中有 1 1 1个为偶数, a n s = gcd ⁡ ( a / 2 , b ) o r gcd ⁡ ( a , b 2 ) ans=\gcd(a/2,b)or\gcd(a,\frac{b}{2}) ans=gcd(a/2,b)orgcd(a,2b)

a , b a,b a,b中有 0 0 0个为偶数, a n s = gcd ⁡ ( a , a − b ) ans=\gcd(a,a-b) ans=gcd(a,ab)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+10,base=1e7,baselen=7;
char A[maxn],B[maxn];
vector<int>a,b;
inline int pd(vector<int>a,vector<int>b)
{
	int lena=a.size(),lenb=b.size();
	if(lena<lenb)
		return -1;
	if(lena>lenb)
		return 1;
	for(register int i=0;i<lena;i++)
	{
		if(a[i]<b[i])
			return -1;
		if(a[i]>b[i])
			return 1;
	}
	return 0;
}
inline void out(vector<int>x)
{
	int len=x.size();
	printf("%lld",x[0]);
	for(register int i=1;i<len;i++)
                printf("%0*lld",baselen,x[i]);
}
inline vector<int> change(vector<int>x)
{
	vector<int>res;
	int len=x.size();
	for(register int i=len-1;i>=0;i--)
		res.push_back(x[i]);
	return res;
}
inline vector<int> Minus(vector<int>a,vector<int>b)
{
	a=change(a);
	b=change(b);
	int alen=a.size(),blen=b.size();
	for(register int i=0;i<blen;i++)
		a[i]-=b[i];
	for(register int i=0;i<alen;i++)
		if(a[i]<0)
		{
			a[i]+=base;
			a[i+1]--;
		}
	while(!a.back() && alen>1)
	{
		a.pop_back();
		alen--;
	}
	a=change(a);
	return a;
}
inline bool odd(vector<int>x)
{
	return x.back()&1;
}
inline vector<int> divide(vector<int>a)
{
	vector<int>res;
	int st=0,len=a.size();
	if(a[0]==1)
	{
		a[1]+=base;
		st=1;
	}
	for(register int i=st;i<len;i++)
	{
		res.push_back(a[i]>>1);
		if(a[i]&1)
			a[i+1]+=base;
	}
	return res;
}
inline vector<int> mult(vector<int>x)
{
	x=change(x);
	int len=x.size();
	for(register int i=0;i<len;i++)
		x[i]<<=1;
	for(register int i=0;i<len-1;i++)
		if(x[i]>=base)
		{
			x[i+1]++;
			x[i]-=base;
		}
	if(x.back()>=base)
	{
		x.push_back(1);
		x[len-1]-=base;
	}
	x=change(x);
	return x;
}
inline vector<int> times(vector<int>a,vector<int>b)
{
	int alen=a.size(),blen=b.size(),clen=alen+blen;
	vector<int>c(clen);
	a=change(a);
	b=change(b);
	for(register int i=0;i<alen;i++)
		for(register int j=0;j<blen;j++)
			c[i+j]+=a[i]*b[j];
	for(register int i=0;i<clen;i++)
		if(c[i]>=base)
		{
			c[i+1]+=c[i]/base;
			c[i]%=base;
		}
	while(clen>1 && !c.back())
	{
		c.pop_back();
		clen--;
	}
	return change(c);
}
inline vector<int> gcd(vector<int>a,vector<int>b)
{
	vector<int>s;
	s.push_back(1);
	for(;;)
	{
		int k=pd(a,b);
		if(k==0)
			return times(a,s);
		if(k<0)
			swap(a,b);
		int oa=odd(a),ob=odd(b);
		if(oa && ob)
			a=Minus(a,b);
		if(!oa && ob)
			a=divide(a);
		if(oa && !ob)
			b=divide(b);
		if(!oa && !ob)
		{
			a=divide(a);
			b=divide(b);
			s=mult(s);
		}
	}
}
signed main()
{
	scanf("%s%s",A+1,B+1);
	int len=strlen(A+1);
	for(register int i=len,x;i>=1;i-=7)
	{
		x=0;
		for(register int j=max(i-6,1ll);j<=i;j++)
			x=x*10+A[j]-48;
		a.push_back(x);
	}
	a=change(a);
	len=strlen(B+1);
	for(register int i=len,x;i>=1;i-=7)
	{
		x=0;
		for(register int j=max(i-6,1ll);j<=i;j++)
			x=x*10+B[j]-48;
		b.push_back(x);
	}
	b=change(b);
	out(gcd(a,b));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值