3.8 NOIP概要

高精度なアルゴリズム

1.精度は何ですか

精度演算、大量に属する処理するための数学的方法。多くの場合、小数点以下の数百以上に考えられ、一般的な科学的な計算では、もちろん、それは大量の数百億数千億である可能性があります。通常、我々は、高精度、高精度演算と呼ばれるそのような数字の数は、加算、減算、乗算、割り算、累乗、階乗、ルート関数のいずれかの大規模なコンピュータシミュレーションデータです。我々は、アレイに、離れていくつかの数の一つに分割、またはいくつかの店舗図番号を表すために配列を使用できるように、非常に多数の適切に、コンピュータに格納されていないことができ、したがって、この図は、高精度の数と呼ばれます。アルゴリズムは正確に高精度デジタル演算の多様を扱うことができるが、なぜなら特殊性には、一般的アルゴリズムの数、教授から単離されます。

このような問題のために、長い二これらの事を期待していない、次の基本データ型を格納することはできません。私たちは、結果を配列に入力文字列として2つの数値を入れ、その後、(小学校に戻っていない場合、)手動垂直動作をシミュレートすることができます。

端的に言えば、高精度の計算が、長い長い解決しようとするも、問題を解決しません。

 

2.精密効果

上述したように、いくつかの高精度な役割のためには不釣り合いに多数のパワー演算階乗ルート関数です。例えば、+ bは、あなたのトピックを与える読み、B、およびあなたが出力することをできるように、しかし、の範囲とbが10未満^ 6666に等しい、この時間は、あなただけの高精度を使用することができます。

 

データを読み出すための3高精度加工

我々は最初に、文字列関数と算術演算を使用して、入力が非常に長い数であることができるように、それぞれの文字列入力を使用できるようにデータの多くは、我々は、任意の整数型セーブ使用する場合配列に、中央値を削除し、我々は各ビット列と番号の各桁を表します。

たとえば、次のビットの整数の他のビットが存在しないので、記憶装置のアレイ、{3,5,3,4,4,2,8,9,9}と998244353下、典型的には、ローからハイに(後方に格納され、しかし、あなたはまた、あなたが)新しいMSBを保存する場所を開く必要があり、最高のレベルを運ぶことができます。

コード読み取り精度

char s[6666];
int a[6666];
 
int main(){
    scanf("%s",s+1);//用字符串读入
    len=strlen(s+1);//这个数的长度为len
    for(int i=1;i<=len;i++){
        a[i]=s[len-i+1]-'0';//倒叙储存,每一位存一个数
    }
    return 0;
}

高精度出力コード 

int a[6666]
 
void write(int a[]){
    for(int i=lena;i>0;i--){
        printf("%d",a[i]);//一位一位输出这个数
    }
}

4.寸法精度コンパレータ

データを処理した後、我々はそれを大行う方法という2つの数値を比較したいと仮定?

私たちは最初のアナログコンパレータ1314520および1314530、二つの数(すなわちLEN1とLEN2)の長さで、最初の私たちを見ている番号少し長くlenの場合、この数は確かに良く、他の大多数よりも、そうでない場合は、我々はここで、それを比較し続けます二つの数字は、そう、我々は2つの最高の数字(すなわち、1、1)を見て、同じ等しいの長さは、比較は次の比較に進み、あまりにも、(3,3)次回続けて...... 10回(2及び3)に特定のビットまで、最初の数<第二の数、出口、3 <2以来。

次のようにそのため、精度の比較がステップ:

1、比较两个数的长度,长度更长的数越大。

2、如果两个数长度相等,那么就从高位到低位一位一位比较,如果某一位数字不同时,较大的数大。否则继续比较下一位。

3、如果比到最后都没有比出谁大谁小,就说明这两个数一样大。

コードサイズの高精度コンパレータ

//比较a和b的大小,如果a>b则返回真,否则返回假
int a[6666],b[6666];
 
int compare(){
    if(lena>lenb) return 1;//lena表示a这个数的长度,lenb则表示b的长度
    if(lenb>lena) return 0;//步骤1
    for(int i=lena;i>0;i--){//从高位到底位一位一位比较
        if(a[i]>b[i]) return 1;
        if(b[i]>a[i]) return 0;
    }//步骤2
    return 0;//步骤3,a=b,即a不大于b
}

高精度加工とボローキャリー

それは持ち運びにまず、私たちはどのように対処しますか?

実際には、非常に単純な、そして、最初我々最下位ビットは16を取得するために追加され、最低レベルの答えは6で、その後1に私たちは何(アナログ大法が良いですが、である必要はありません)、1439 + 887をシミュレートしてみましょう、10の二つの数字、3 + 8 = 11を付加し進捗を追加1ビット、11 + 1 = 12であるので、答えは10 2で、次いで8 + 4 + 1 = 13に、百の答え1,1 + 0 + 1 = 2に、3ビット、答えは千2です。結果はとても6232です!ああ、後方、それは2326年で、ああ、ここでは出力の出力が後方のとき、忘れてはいけない、に注意を払う必要がありません。

次のように、キャリーの手順を要約すると:

1、将当前位置的数相加,当前位的结果就是当前结果除以10的余数。

2、再讲当前结果除以10加到高位,表示进位。

注:一部の学生は疑問であってもよく、なぜそれが逆方向にこの番号を格納する必要がありますか?預金ダウンしていない良いですか?私は、このような10 + 90として、誰もがその答えは、我々は見ての後方違い何店舗と店舗テイクダウン、100であることを知っている、あなたは非常に簡単な例を挙げてみましょう:

1.顺着存:a={1,0},b={9,0},当a的最高位(即数组第1位)加上b的最高位(即数组第2位)时我们是不是得进位?!?但是a的最高位是数组的第一位,那么我们要进位到a数组的第几个位置呢?第0个位置?太复杂了。还是存在第一个位置并把所有的数往数组右边移动一位?那更不行,时间复杂度又太高,所以不好办。

2.倒着存:a={0,1},b={0,9},当a的最高位(即数组第2位)加上b的最高位(即数组第2位)时我们同样要进位,这个时候就好办了,直接进位到数组的第三位就好了,所以答案的数组就是{0,0,1},倒过来输出答案100。

キャリー精密コード

int a[6666],b[6666],c[6666];
int lena,lenb,lenc;
 
int main(){
    lenc=max(lena,lenb);
    for(int i=1;i<=lenc;i++){
        c[i]=c[i]+a[i]+b[i];
        c[i+1]=c[i]/10;
        c[i]=c[i]%10;
    }
    while(c[lenc+1]>0) lenc++;//答案的长度有时还会增加
}

 第二に、減算ボローについて話をする方法を次の時間

1、将当前位置的数向减。

2、如果结果大于或等于0就直接作为当前位的答案。

3、否则将结果加10作为当前位的答案,在将高位的数-1即可。

精密ボローコード

int a[6666],b[6666],c[6666];
int lena,lenb,lenc;
 
int main(){
    lenc=max(lena,lenb);
    for(int i=1;i<=lenc;i++){
        c[i]=c[i]+a[i]-b[i];
        if(c[i]<0) c[i]=c[i]+10,c[i+1]=-1;
    }
    while(c[lenc]==0&&lenc>1) lenc--;//细节,如果a-b结果为0,那么也要输出一个0
}

高精度の加算器

 この時点で、あなたはあなたがしたい任意の操作を行うことができ、実際には、上記のコードはほとんど出て書かれている最初の私たちが見て追加を取る、されています。

精密加算コード

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
int a[6666],b[6666],c[6666];
int lena,lenb,lenc;
char s1[6666],s2[6666];
 
int main(){
    scanf("%s %s",s1+1,s2+1);
    lena=strlen(s1+1);
    lenb=strlen(s2+1);
    for(int i=1;i<=lena;i++) a[i]=s1[lena-i+1]-'0';
    for(int i=1;i<=lenb;i++) b[i]=s2[lenb-i+1]-'0';
    lenc=max(lena,lenb);
    for(int i=1;i<=lenc;i++){
        c[i]=c[i]+a[i]+b[i];
        c[i+1]=c[i]/10;
        c[i]=c[i]%10;
    }
    while(c[lenc+1]>0) lenc++;
    for(int i=lenc;i>0;i--) printf("%d",c[i]);
}

7.精密減算

精密減算コード

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
int a[6666],b[6666],c[6666];
int lena,lenb,lenc;
char s1[6666],s2[6666];
 
int main(){
    scanf("%s %s",s1+1,s2+1);
    lena=strlen(s1+1);
    lenb=strlen(s2+1);
    if(lenb>lena||(lena==lenb&&s2>s1)){//如果第二个数比第一个数大,那么结果是负数
        printf("-");
        swap(s1,s2);//swap是C++自带函数可以直接调用
        swap(lena,lenb);//别忘了交换长度
    }
    for(int i=1;i<=lena;i++) a[i]=s1[lena-i+1]-'0';
    for(int i=1;i<=lenb;i++) b[i]=s2[lenb-i+1]-'0';
    lenc=max(lena,lenb);
    for(int i=1;i<=lenc;i++){
        c[i]=c[i]+a[i]-b[i];
        if(c[i]<0) c[i]=c[i]+10,c[i+1]=-1;
    }
    while(c[lenc]==0&&lenc>1) lenc--;
    for(int i=lenc;i>0;i--) printf("%d",c[i]);
}

8.精度乗算

1.高精度単精度乗算

コードを乗算精密単精度

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
int a[6666],b;
int lena;
char s1[6666];
 
int main(){
    scanf("%s %d",s1+1,&b);
    lena=strlen(s1+1);
    for(int i=1;i<=lena;i++) a[i]=s1[lena-i+1]-'0';
    for(int i=1;i<=lena;i++) a[i]*=b;
    for(int i=1;i<=lena;i++){
        a[i+1]+=a[i]/10;
        a[i]%=10;
    }
    while(a[lena+1]>0) lena++;
    for(int i=lena;i>0;i--) printf("%d",a[i]);
}

2.精度は、精度を乗じ

精度は精密コードを乗算します

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
int a[6666],b[6666],c[6666];
int lena,lenb,lenc;
char s1[6666],s2[6666];
 
int main(){
    scanf("%s %s",s1+1,s2+1);
    lena=strlen(s1+1);
    lenb=strlen(s2+1);
    for(int i=1;i<=lena;i++) a[i]=s1[lena-i+1]-'0';
    for(int i=1;i<=lenb;i++) b[i]=s2[lenb-i+1]-'0';
    lenc=lena+lenb-1;
    for(int i=1;i<=lena;i++){
        for(int j=1;j<=lenb;j++){
            c[i+j-1]+=a[i]*b[j];
            c[i+j]+=c[i+j-1]/10;
            c[i+j-1]%=10;
        }
    }
    while(c[lenc+1]>0) lenc++;
    for(int i=lenc;i>0;i--) printf("%d",c[i]);
}

最大公約数、最小公倍数。

最大公約数機能を構築することができます。

__gcd(a,b);

最大公約数を手書き推奨使用方法:

int gcd(int a,int b)
{
    if (b==0) return a;
    else return gcd(b,a%b);
}

乗算二つの数に応じて最小公倍数言葉は、そのGCD * LCMを得ることができるに等しいです。

高速電力

コードの最初の

typedef long long ll;
ll quick_pow(ll x,ll n,ll m){
    ll res = 1;
    while(n > 0){
        if(n & 1)   res = res * x % m;
        x = x * x % m;
        n >>= 1;//相当于n=n/2.详情请参考位移运算符。
    }
    return res;
} 

それを仮定する必要X ^ N、N = 2 ^ K、元の問題は容易ように表すことができる場合、X ^ N =((X ^ 2)^ 2)^ 2 .... 限りk倍正方形操作(n)をログに記録するO(N)の時間計算量を減少させるために、解決することができるように行います。

    上記の分析から、電力べき乗を2 ^ kの形で書くことができる限り、時間複雑度は、上記の方法を用いて低減することができます。私たちは、有限数kの形で任意の実数のn ^ 2を書き​​換えることができるように追加されます。

行列

まず、行列の基礎

行列演算は、行列加算、減算、乗算、乗算、転置、複合体、および共役転置を含みます

二つ、C ++コードのその実装加算、減算、乗算、乗算、転置

1、加算、減算、乗算、実現の乗算

#include <iostream>
#include <malloc.h>
#include <stdio.h>
using namespace std;

typedef struct
{
//结构体
int row,col;
//二维指针,目的是动态分配内存
float **matrix;
} Matrix;

typedef struct
{
char *name;
char *number;
} Student;

Matrix CreateMatrix()
{
Matrix m;
int row,col;
cout << "输入行数与列数:" << endl;
cin >> row >> col;
float **enterMatrix ;
enterMatrix=(float**) malloc(row*sizeof(float*)) ;
for(int i=0; i<row; i++)
enterMatrix[i] = (float *)malloc(col * sizeof(float));
cout<<"输入你的矩阵:"<<endl;
for(int i=0; i<row; i++)
{
for(int j=0; j<col; j++)
{
cin >> enterMatrix[i][j];
}
}
m.col = col;
m.row = row;
m.matrix = enterMatrix;
return m;
}

//初始化一个行为row列为col矩阵
Matrix InitMatrix(int row,int col)
{
Matrix m;
float **matrix ;
matrix=(float**) malloc(row*sizeof(float*)) ;
for(int i=0; i<row; i++)
matrix[i] = (float *)malloc(col * sizeof(float));
for(int i=0; i<row; i++)
{
for(int j=0; j<col; j++)
{
matrix[i][j] = 0;
}
}
m.col = col;
m.row = row;
m.matrix = matrix;
return m;
}

//加法

Matrix add(Matrix m1, Matrix m2)

{
for(int i=0; i<m1.row; i++)
{
for(int j=0; j<m1.col; j++)
{
m1.matrix[i][j] = m1.matrix[i][j] +m2.matrix[i][j];
}
}
return m1;
}

 //减法

Matrix sub(Matrix m1, Matrix m2)
{
for(int i=0; i<m1.row; i++)
{
for(int j=0; j<m1.col; j++)
{
m1.matrix[i][j] = m1.matrix[i][j] -m2.matrix[i][j];
}
}
return m1;
}

int calRowCol(Matrix M1,Matrix M2,int row,int col)//row为M1的行 col为m2的列
{
int result = 0;
int same = M1.col;
for(int j=0; j<same; j++)
{
result+=M1.matrix[row][j]*M2.matrix[j][col];
}

return result;
}

//乘法
Matrix Mul(Matrix m1, Matrix m2)
{
Matrix result = InitMatrix(m1.row,m2.col);
for(int i=0; i<m1.row; i++)
{
for(int j=0; j<m2.col; j++)
{
result.matrix[i][j] = calRowCol(m1,m2,i,j);
}
}
return result;
}

//数乘

Matrix numMul(Matrix m, int num)
{
cout<<"数值:"<<num<<endl;
for(int i=0; i<m.row; i++)
{
for(int j=0; j<m.col; j++)
{
m.matrix[i][j] = m.matrix[i][j]*num;
}
}
return m;
}

//输出

Matrix printMatrix(Matrix m)

{
for(int i=0; i<m.row; i++)
{
for(int j=0; j<m.col; j++)
{
cout << m.matrix[i][j] << " ";
}
cout<<endl;
}
}

int main()
{
int num = 0;
do
{
cout<<"*************************************\n";
cout<<"* 菜单 *\n";
cout<<"* 1.矩阵相加 *\n";
cout<<"* 2.矩阵相减 *\n";
cout<<"* 3.矩阵相乘 *\n";
cout<<"* 4.矩阵数乘 *\n";
cout<<"* 5.退出 *\n";
cout<<"*************************************\n";
cin>>num;
if(1 == num|| 2 == num || 3 == num)
{
cout<<"请输入矩阵1"<<endl;
Matrix m1 = CreateMatrix();
cout<<"请输入矩阵2"<<endl;
Matrix m2 = CreateMatrix();
cout<<"两矩阵为"<<endl;
printMatrix(m1);
cout<<endl;
printMatrix(m2);
switch(num)
{
case 1:
{
if(m1.col!=m2.col || m1.row!=m2.row)
{
cout<<"行列不同"<<endl;
}
else{
cout<<"结果为:"<<endl;
printMatrix(add(m1,m2));
}
break;
}
case 2:
{
if(m1.col!=m2.col || m1.row!=m2.row)
{
cout<<"参数错误"<<endl;
}
else{
cout<<"结果为:"<<endl;
printMatrix(sub(m1,m2));
}
break;
}
case 3:
{
if(m1.col!=m2.row)
{
cout<<"参数错误"<<endl;
}
else{
cout<<"结果为:"<<endl;
printMatrix(Mul(m1,m2));
}
break;
}
default:
break;
}
}
else if(4 == num)
{
int number = 1;
cout<<"请输入矩阵"<<endl;
Matrix m = CreateMatrix();
cout<<"请输入数值"<<endl;
cin>>number;
cout<<"矩阵为:"<<endl;
printMatrix(m);
cout<<"数值为:"<<endl;
cout<<number<<endl;
printMatrix(numMul(m,number));
}
cout<<"按回车继续....";
getchar();
getchar();
system("cls");
}
while(1 == num|| 2 == num || 3 == num ||4 == num);
return 0;
}

行列転置行列所与2、

  //n阶矩阵求转置,也就是沿着左对角线反转矩阵;a[i][j]  与 a[j][i] 对换。

#include<iostream>
using namespace std;
template<class T>
void swap(T* a, T* b)
{
T temp = a;
*a = *b;
*b = temp;
return;
}
template<class T>
void transpose(T& a, int rows)
{
for (int i = 0; i < rows; i++)
{
for (int j = i + 1; j < rows; j++)
{
swap(a[i][j], a[j][i]);
}
}
return;
}
int main()
{
int a[3][3] = { 1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
transpose(a, 3);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}

//n * m矩阵的转置,行和列颠倒。

#include<iostream>
using namespace std;
template<class T>
void swap(T* a, T* b)
{
T temp = a;
*a = *b;
*b = temp;
return;
}
template<class T,class T1>
void transpose(T& a, T1& b,int rows,int cols)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
b[j][i] = a[i][j];
}
}
return;
}
int main()
{
int a[4][3] = { 1,2,3,4,5,6,1,2,3,4,5,6 };
int b[3][4] = { 0 };
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
transpose(a,b,4,3);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
cout << b[i][j] << " ";
}
cout << endl;
}
return 0;
}

おすすめ

転載: www.cnblogs.com/Kyriech-Francis/p/12453519.html