基礎算法二

高精度(C++)問題:
一共考4種問題:

  1. 大整數相加 A+B A,B<=10的6次方
  2. 大整數相減 A,B<=10的6次方
  3. 大整數相乘 A<=10的6次方, a<=10的9次方
  4. 大整數相除 A<=10的6次方, a<=10的9次方

// java有大整數類,python是無限大,不需要。
大整數是很大的,用字符數組寫入。
0 1 2 3 4 5 6 7 8
9 8 7 6 5 4 3 2 1
先寫低位存儲大整數。浮點數用太少,暫時不學了。。。
小學學的加法是先低位進位再得結果:
1 2 3
8 9
—.–.------
2 1 2
大於10進位,不大於10不進位。
高精度加法1:
code1:

#include<iostream>
using namespace std;
//const int N=1e6+10;
//C=A+B;

vector<int> add(vector<int> &A,vector<int> &B){
	vector<int> C;
	int t=0;
	for(int i=0;i<A.size()||i<B.size();i++){
		if(i<A.size()) t+=A[i];
		if(i<B.size()) t+=B[i];
		C.push_back(t%10);
		t/=10;
	}
		if(t)C.push_back(1);
		return C;
}

int main(){
	string a,b;
	vector<int> A,B;
	cin>>a>>b;//a="123456"
	for(i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
for(i=b.size()-1;i>=0;i--) 	  B.push_back(b[i]-'0');
		auto C=add(A,B);//auto是編譯器可以自己推斷變量類型
		for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
	return 0;
}


換一下寫法,提前判斷:

#include<iostream>
using namespace std;
//const int N=1e6+10;
//C=A+B;

vector<int> add(vector<int> &A,vector<int> &B){
	vector<int> C;
	if(A.size()<B.size()) return add(B,A);
	int t=0;
	for(int i=0;i<A.size();i++){
		 t+=A[i];
		if(i<B.size()) t+=B[i];
		C.push_back(t%10);
		t/=10;
	}
		if(t)C.push_back(1);
		return C;
}

int main(){
	string a,b;
	vector<int> A,B;
	cin>>a>>b;//a="123456"
	for(i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
for(i=b.size()-1;i>=0;i--) 	  B.push_back(b[i]-'0');
		auto C=add(A,B);//auto是編譯器可以自己推斷變量類型
		for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
	return 0;
}

大數減法:
A3 A2 A1 A0
B2 B1 B0

判斷Ai-Bi-t>=0  :Ai-Bi-=t
判斷Ai-Bi-t<0  :Ai-Bi+10=t

  分兩種情況:
  A>=B: A-B;
  a<b : -(B-A);
  
  code:
#include<iostream>
using namespace std;
//const int N=1e6+10;
//C=A+B;
bool cmp(vector<int> &A,vector<int> &B){
if(A.size()!=B.size()) return A.size()>B.size();
for(int i=A.size();i>=0;i--)
if(A[i]!=B[i])
return A[i]>B[i];
return true;
}
vector<int> sub(vector<int> &A,vector<int> &B){
		vector<int> C;
		for(int i=0,t=0;i<A.size();i++){
		t=A[i]-t;
		if(i<B.size()) t-=B[i];
		C.push_back((t+10)%10);
		if(t<0) t=1;
		else t=0;
	}	
	//前導0 指的是
	/*
	1 2 3
	1 2 0
---------------
	0 0 3//這裏的0就是前導0
	*/
	while(C.size()>1&&c.back()==0)  c.pop_back();//去掉前導0
	return C;	
}
int main(){
	string a,b;
	vector<int> A,B;
	cin>>a>>b;//a="123456"
	for(i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
for(i=b.size()-1;i>=0;i--) 	  B.push_back(b[i]-'0');
		if(cmp(A,B)){
		auto C=sub(A,B);//auto是編譯器可以自己推斷變量類型
		for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
		}
	return 0;
}

高精度乘法:
說明一個問題:
1 2 3
1 2


t3 t2 t1

C3 C2 C1

C0=(3x12)%10=6;

t1=(3*12)/10 =3;

C1=(2X12+t+%10=7

t2=2

C2=(1*12)%10=1

t3=1

C3=1
以上問題 說明了一個模運算和權重爲10的變化。

code:

#include<iostream>
#include<vector>
using namespace std;
const int N=1e6+10;
//C=A+B;

vector<int> mul(vector<int> &A,int b){
	vector<int> C;
	int t=0;//第0位進位 
	for(int i=0;i<A.size()||t;i++){
		if(i<A.size()) t+=A[i]*b;
		C.push_back(t%10);//取個位
		t/=10; 
	}

		return C;
}

int main(){
	string a;
	int b;
	vector<int> A;
	cin>>a>>b;
	for(i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');//a[i]-'0' 是字符數組轉到真實的整數。 常見字符ASCLL碼:A :97 ,a: 65,0:48

		auto C=mul(A,b);
		for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
	return 0;
}


大數的除法

#include<iostream>
#include<vector>
using namespace std;
const int N=1e6+10;
//C=A+B;

vector<int> div(vector<int> &A,int b,int &r){
	vector<int> C;
	r=0;
	for(int i=A.size();i>=0;i--){
  r=r*10+A[i];
  C.push_back(r/b);
  r%=b;
}
	
reverse(C.begin(),C.end());
while(C.size()>1&&C.back()==0) c.pop_back();//去掉最高位
		return C;
}

int main(){
	string a;
	int b;
	vector<int> A;
	cin>>a>>b;
	for(i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');//a[i]-'0' 是字符數組轉到真實的整數。 常見字符ASCLL碼:A :97 ,a: 65,0:48

		auto C=div(A,b,r);
		for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
		cout<<endl<<r<<endl;
	return 0;
}

前綴和
算是一個遞推式子
:Si=a1+a2+…+an, s0=0.
2.如何算 Sn. S[i]=S[i-1]+an.
3,.作用 : O(n)—> O(1)的複雜度變化
兩個式子相減得出:遞推式
code:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+10;
int n,m;
int a[N],s[N];


int main(){
	ios::sync_with_stdio(false);//提高cin的速度,但是不能再用scanf ,速度還是小於scanf 
	//scanf("%d%d",&n,&m);
	cin>>n>>m;
	for(int i=1;i<n;i++) cin>>a[i];
	for(int i=1;i<n;i++) s[i]=s[i-1]+a[i];//前綴和得初始化
	while(m--){
		int l,r;
		cin>>l>>r;
		printf("%d\n",s[r]-s[l-1]);//區間和的計算 
	} 
	return 0;
}

子矩陣的和
容斥原理思考一下可好。
code:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=10010;
int n,m,q;
int a[N][N],s[N][N];


int main(){
//	ios::sync_with_stdio(false);//提高cin的速度,但是不能再用scanf ,速度還是小於scanf 
scanf("%d%d",&n,&m,&q);
	//cin>>n>>m>>q;
	for(int i=1;i<n;i++)  
	for(int j=1;j<m;j++) 
//	cin>>a[i][j];
scanf("%d",&a[i][j]);
	for(int i=1;i<n;i++)  
	for(int j=1;j<m;j++) 
	s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//求前綴和
	while(q--){
		int x1,y1,x2,y2;
	//	cin>>x1>>y1>>x2>>y2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);//算部分和
			}
	return 0;
}

差分:
本質是: 前綴和的逆運算
a1,a2,…an
構造b1,b2,b3,…bn
a數組是b數組的差分,b數組是a數組的前綴和,類似積分與微分。
b1=a1;
b2=a2-a1;
b3=a3-a2;
bn=b1+b2+b3+…
【l,r】+C,a1+C,a2+C,a3+C,…an+C. 差分實現時間複雜度爲O(1),給原數組每個元素加上固定的值。
l-------->r
b(l+c)------->a(l+c)

code:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100010;
int m,n;
int a[N],b[N];

void insert(int l,int r,int c){
	b[l]+=c;
	b[r+1]-=c;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) insert(i,i,a[i]);
	while(m--){
		int l,r,c;
		scanf("%d%d%d",&l,&r,&c);
			insert(l,r,c);
	}
	for(int i=1;i<=n;i++) b[i]+=b[i-1];
	for(int i=1;i<=n;i++) printf("%d",b[i]);
	
	
	return 0;
}

2:00暫停

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章