真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

XCPC歷險(xiǎn)記第二章!帶你玩轉(zhuǎn)高精度、前綴和與差分!-創(chuàng)新互聯(lián)

文章目錄
  • 一、高精度剖析與例題講解
    • 1.A+B(A,B位數(shù)很大,如1e6級(jí)別)
    • 2.A-B(A,B位數(shù)很大,如1e6級(jí)別)
    • 3.A*b(A的位數(shù)很大,如1e6級(jí)別;但b相較A很小,如b的值在1e6級(jí)別)
    • 4.A/b(A的位數(shù)很大,如1e6級(jí)別;但b相較A很小,如b的值在1e6級(jí)別
  • 二、前綴和、差分剖析與例題講解
    • 二、1.前綴和
      • 二、1、1.前綴和的求法
      • 二、1、2.前綴和的作用
    • 二、2.二維前綴和
      • 二、2.1二維前綴和的作用
      • 二、2.1前綴和的求法
    • 二、3.差分
      • 二、4.二維差分

在這里插入圖片描述

創(chuàng)新互聯(lián)成都企業(yè)網(wǎng)站建設(shè)服務(wù),提供成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)網(wǎng)站開(kāi)發(fā),網(wǎng)站定制,建網(wǎng)站,網(wǎng)站搭建,網(wǎng)站設(shè)計(jì),成都響應(yīng)式網(wǎng)站建設(shè)公司,網(wǎng)頁(yè)設(shè)計(jì)師打造企業(yè)風(fēng)格網(wǎng)站,提供周到的售前咨詢和貼心的售后服務(wù)。歡迎咨詢做網(wǎng)站需要多少錢(qián):13518219792一、高精度剖析與例題講解

高精度問(wèn)題是一類處理長(zhǎng)度(位數(shù))很長(zhǎng)的正整數(shù)的運(yùn)算問(wèn)題(以下均討論非負(fù)數(shù))。在學(xué)習(xí)具體的問(wèn)題之前,我們首先要學(xué)習(xí)超長(zhǎng)整數(shù)是如何存儲(chǔ)的。對(duì)于超長(zhǎng)整數(shù),用某種數(shù)據(jù)類型來(lái)存儲(chǔ)其實(shí)是行不通的,我們會(huì)把它的每一位存到數(shù)組里。在存儲(chǔ)時(shí),數(shù)組的小下標(biāo)存低位,大下標(biāo)存高位。比如若把123456(當(dāng)然它不是超長(zhǎng)整數(shù),我們只是舉個(gè)例子)存到數(shù)組里,那么就是6 5 4 3 2 1。這樣做是因?yàn)榧訙p乘除可能涉及到進(jìn)位,而在數(shù)組尾部進(jìn)行數(shù)據(jù)的修改是比較容易的。注意:不要混淆位數(shù)和數(shù)值!比如說(shuō),若一個(gè)數(shù)的數(shù)值<=10,那么它的取值范圍是0-10;若一個(gè)數(shù)的長(zhǎng)度<=10,那么它的取值范圍是0-9999999999。
高精度問(wèn)題主要分為以下幾類:

1.A+B(A,B位數(shù)很大,如1e6級(jí)別)

讓我們先來(lái)回憶一下豎式加法的流程:
在這里插入圖片描述

這里的ti(i = 0,1,2,3)表示進(jìn)位,因此ti = 0或1。我們可以發(fā)現(xiàn),Ci = (Ai + Bi + ti)%10。因此要實(shí)現(xiàn)超長(zhǎng)整數(shù)相加,只需要把數(shù)組對(duì)應(yīng)位置的數(shù)以及進(jìn)位數(shù)加起來(lái)再模10,就可以得到新數(shù)字的每一位。 那么就讓我們來(lái)看看代碼如何實(shí)現(xiàn)吧!
在這里插入圖片描述

#include#includeusing namespace std;
//傳引用,防止多開(kāi)空間
vectoradd(vector&A,vector&B)
{vectorC;
    //保存進(jìn)位
    int t = 0;
    for(int i = 0;iif(i//用字符串的形式讀數(shù),可以拿到每一位
    string a,b;
    //定義大小可變化的數(shù)組
    vectorA,B;
    cin>>a>>b;
    //由于讀進(jìn)來(lái)的形式是字符,因此為了拿到那一位,我們要減去偏移量,即字符0的ASCII碼值。
    //此外,我們要把數(shù)據(jù)倒著讀進(jìn)數(shù)組。
    for(int i = a.size()-1;i>=0;i--)    A.push_back(a[i]-'0');
    for(int i = b.size()-1;i>=0;i--)    B.push_back(b[i]-'0');
    
    vectorC = add(A,B);
    //倒著打印
    for(int i = C.size()-1;i>=0;i--)    printf("%d",C[i]);
    
    return 0;
}

一定要好好看注釋哦,作者想說(shuō)的都在注釋里啦!如果你感覺(jué)閱讀本段代碼有困難,不妨先看看這個(gè)——[
C++vector快速入門(mén)

2.A-B(A,B位數(shù)很大,如1e6級(jí)別)

數(shù)據(jù)的存儲(chǔ)方式同上。那么相減的算法思想是怎樣的呢?我們通過(guò)豎式計(jì)算圖來(lái)觀察一下:
在這里插入圖片描述
我們可以發(fā)現(xiàn),與加法不同的是減法需要借位。假設(shè)上一位借該位t(t=0或1),那么

>=0 不需要借位 那么直接減就可以 得到Ai - Bi - t
Ai - Bi - t
<0 那么需要借位,也就是+10,得到Ai -Bi - t + 10

在這里插入圖片描述

#includeusing namespace std;
#include//判斷是否有 A>=B
bool cmp(vector&A,vector&B)
{if(A.size()!=B.size())  return A.size()>B.size();
    for(int i = A.size()-1;i>=0;i--)
    {if(A[i]!=B[i])  return A[i]>B[i];
    }
    return true;
}

//C = A - B
//這里已經(jīng)保證A>=B了
vectorsub(vector&A,vector&B)
{vectorC;
    //由于已經(jīng)保證A>=B,所以A.size()>=B.size()
    for(int i = 0,t = 0;i//t為0表示不借位,為1表示借位
        //與上面的高精度加法不同的是,這里的t不方便更新,所以我們應(yīng)該把t定義在循環(huán)里面,這樣方便每次循環(huán)的時(shí)候更新重置!
        t = A[i] - t;
        //防止越界
        if(i0,就應(yīng)該賦t給C。那么把二者結(jié)合起來(lái)就是下面的寫(xiě)法:
        C.push_back((t+10)%10);
        
        if(t<0) t = 1;
        else    t = 0;
    }
    //若出現(xiàn)形如003這樣的結(jié)果,把0去掉
    while(C.size()>1&&C.back()==0)  C.pop_back();
    
    return C;
}

int main()
{string a,b;
    cin>>a>>b;
        vectorA,B,C;
    for(int i = a.size()-1;i>=0;i--)    A.push_back(a[i] - '0');
    for(int i = b.size()-1;i>=0;i--)    B.push_back(b[i] - '0');
    
    if(cmp(A,B))
    {C = sub(A,B);
        for(int i = C.size()-1;i>=0;i--)    printf("%d",C[i]);
    }
    else
    {C = sub(B,A);
        printf("-");
        for(int i = C.size()-1;i>=0;i--)    printf("%d",C[i]);
    }
    
    
}
3.A*b(A的位數(shù)很大,如1e6級(jí)別;但b相較A很小,如b的值在1e6級(jí)別)

首先,我們應(yīng)該明白人類是怎么計(jì)算乘法的~~舉一個(gè)例子看看吧!

**由于高精度乘法要把a(bǔ)看作整體,所以這里的相乘步驟與我們熟悉的逐位相乘略有不同,但原理是一樣的:
在這里插入圖片描述
我們可以看出乘法和加法的進(jìn)位規(guī)則是類似的,下面讓我們用代碼來(lái)實(shí)現(xiàn)它吧!
在這里插入圖片描述

#includeusing namespace std;
#includevectormul(vector&A,int&b)
{vectorC;
    int t = 0;
    //如果這里不加||t(即t!=0),會(huì)把結(jié)果的最高位(也就是C數(shù)組的最后一個(gè)元素)弄丟!
    //與加法不同的是,這里我們嘗試把一個(gè)循環(huán)和一個(gè)判斷(關(guān)于t的判斷)放到一塊了
    for(int i = 0;iif(i1&&C.back()==0)  C.pop_back();
    return C;
}
int main()
{string a;
    int b;
    cin>>a>>b;
    vectorA,C;
    
    for(int i = a.size()-1;i>=0;i--)    A.push_back(a[i] - '0');
    
    C = mul(A,b);
    
    for(int i = C.size()-1;i>=0;i--)    printf("%d",C[i]);
    
    return 0;
}
4.A/b(A的位數(shù)很大,如1e6級(jí)別;但b相較A很小,如b的值在1e6級(jí)別

我們還是先看看人類是怎么計(jì)算除法的。
在這里插入圖片描述
(以下ri表示余數(shù),初始r0設(shè)定為0)
我們可以發(fā)現(xiàn),C3 = A3/b,r1 = (A3 % b)*10+A2,C2 = r1/b,r2 = (r1%b)*10+A3,C3 = r2/b,r3 = (r2%b)*10+A4,C4 = r3/b。
那么如何用代碼實(shí)現(xiàn)這一過(guò)程呢?
在這里插入圖片描述

#includeusing namespace std;
#include#include

vectordiv(vector&A,int&b,int&r)
{vectorC;
    //r為余數(shù),初始值為0
    r = 0;
    for(int i = A.size()-1;i>=0;i--)
    {r = r*10+A[i];
        C.push_back(r/b);
        r%=b;
    }
    //翻轉(zhuǎn)數(shù)組
    reverse(C.begin(),C.end());
    //也要去掉前導(dǎo)0
    while(C.size()>1&&C.back()==0)  C.pop_back();
    return C;
}
int main()
{string a;
    int b;
    
    cin>>a>>b;
    
    vectorA;
    for(int i = a.size()-1;i>=0;i--)  A.push_back(a[i] - '0');
    
    int r = 0;
    vectorC;
    C = div(A,b,r);
    
    for(int i = C.size()-1;i>=0;i--)  printf("%d",C[i]);
    cout<

說(shuō)明1:與加、減、乘不一樣的是,除法的運(yùn)算是從最高位開(kāi)始的。那么按道理來(lái)說(shuō),我們并不需要把超長(zhǎng)整數(shù)倒著存進(jìn)數(shù)組里。但是一道題目中往往加減乘除混雜,為了統(tǒng)一,我們?nèi)匀徊捎玫怪孢M(jìn)數(shù)組倒著打印的方式。而也正因?yàn)槿绱?,div函數(shù)中i要從A.size-1開(kāi)始,即倒著讀。那么得到的C數(shù)組也要翻轉(zhuǎn)。
說(shuō)明2:通過(guò)前面四個(gè)例子的分析,我們可以注意到,對(duì)于某個(gè)變量k,若在循環(huán)中寫(xiě)成k = f(k)(這里f(k)是關(guān)于k的表達(dá)式),那么其實(shí)是一種遞推!

二、前綴和、差分剖析與例題講解 二、1.前綴和

前綴和是一個(gè)數(shù)組中前i項(xiàng)的和,記作Si。若一個(gè)數(shù)組為:a1,a2,a3,a4,……那么Si = a1 + a2 + a3 + …… + ai。

二、1、1.前綴和的求法

觀察可知,Si = S(i-1) + ai。(記S0 = 0,便于處理邊界)。

二、1、2.前綴和的作用

前綴和可以用來(lái)計(jì)算數(shù)組中一段數(shù)據(jù)的和。例如要求數(shù)組中【l,r】區(qū)間的和,我們可以用Sr - S(l - 1)。
接下來(lái)讓我們看看具體的代碼實(shí)現(xiàn)吧!
在這里插入圖片描述

#includeusing namespace std;

const int N = 1e6+10;

int n,m;
int a[N],s[N];

int main()
{scanf("%d%d",&n,&m);
    for(int i = 1;i<=n;i++) scanf("%d",&a[i]);
    
    s[0] = 0;
    //這是迭代!這不是遞歸!
    for(int i = 1;i<=n;i++) s[i] = s[i-1]+a[i];
    
    while(m--)
    {int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",s[r] - s[l-1]);
    }
    return 0;
}
二、2.二維前綴和

二維前綴和是一個(gè)矩陣某點(diǎn)左上角全部元素(包括該點(diǎn))的和。例如有某個(gè)m*n矩陣A,那么(i,j)點(diǎn)的前綴和S(i,j)= a(1,1)+a(1,2)+……+a(1,j)+……+a(i,j)。在解決前綴和相關(guān)問(wèn)題時(shí),我們不妨把“和”看作“面積”,這樣會(huì)直觀一些。

二、2.1二維前綴和的作用

二維前綴和可以用來(lái)計(jì)算矩陣某一個(gè)區(qū)域內(nèi)所有數(shù)據(jù)的和。例如:
在這里插入圖片描述
那么從(i1,j1)到(i2,j2)的所有數(shù)據(jù)的和為:
S = S(i2,j2)- S(i1,j2 - 1)- S(i2,j1 - 1)+ S(i1 - 1,j1 - 1)(因?yàn)樽笊辖堑男^(qū)域被減了兩次,所以要加回來(lái))

二、2.1前綴和的求法

觀察圖可知,S(i,j)= S(i - 1,j)+ S(i,j-1)- S(i-1,j-1)(因?yàn)楸患恿藘纱?,所以要減掉)+ a(i,j)。
有了上面的了解,我們就可以來(lái)看看代碼模板了。
在這里插入圖片描述

#includeusing namespace std;

const int N = 1010;

int n,m,q;
int a[N][N],s[N][N];

int main()
{//注意:若不給數(shù)組初始化,默認(rèn)全部元素為0
    scanf("%d%d%d",&n,&m,&q);
    //注意:這里要從i=1,j=1開(kāi)始!因?yàn)閍數(shù)組下標(biāo)從1開(kāi)始會(huì)更方便些
    for(int i = 1;i<=n;i++)
        for(int j = 1;j<=m;j++)
            scanf("%d",&a[i][j]);
    //注意:這里也要從i=1,j=1開(kāi)始!這樣i-1、j-1以后才能從零開(kāi)始
    //迭代求前綴和
    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];
    //多組詢問(wèn)
    while(q--)
    {int 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;
            
}
二、3.差分

差分是前綴和的逆運(yùn)算。設(shè)已經(jīng)有一個(gè)數(shù)組a1,a2,a3,a4……,這個(gè)數(shù)組的差分是指這樣一個(gè)數(shù)組:它的前綴和為原數(shù)組。那么我們很容易就可以構(gòu)造出差分?jǐn)?shù)組:b1 = a1,b2 = a2 - a1,b3 = a3 - a2,b4 = a4 - a3……但實(shí)際上這個(gè)構(gòu)造并不重要,只要我們觀念上知道有一個(gè)構(gòu)造即可。
差分的方法在什么時(shí)候有用呢?比如說(shuō)我們要執(zhí)行這樣的操作:把a(bǔ)數(shù)組中【l ,r】?jī)?nèi)的數(shù)全部加上某個(gè)常數(shù)c,如果運(yùn)用差分,把查分?jǐn)?shù)組中的bl + c,b(r+1) - ? c,那么由于b是a的差分?jǐn)?shù)組,【l,r】?jī)?nèi)的數(shù)就自動(dòng)全加上c了。而對(duì)于數(shù)組a,我們可以這樣看:它初始的時(shí)候所有值為0,然后我們賦值時(shí)每次插入。
接下來(lái)讓我們看看例題和解答代碼吧!
在這里插入圖片描述

using namespace std;

const int N = 100010;

int n, m;
//b是差分?jǐn)?shù)組
int a[N], b[N];
//讓b[l] + c,b[r+1]-c
void insert(int l, int r, int c)
{b[l] += c;
    b[r + 1] -= c;
}

int main()
{scanf("%d%d", &n, &m);
    //a、b數(shù)組下標(biāo)都從1開(kāi)始即可,因?yàn)檫@里沒(méi)有邊界條件
    for (int i = 1; i<= n; i ++ ) scanf("%d", &a[i]);
    //構(gòu)造差分?jǐn)?shù)組。由于最開(kāi)始a、b數(shù)組中的元素全為0,因此最開(kāi)始的時(shí)候b就是a的差分?jǐn)?shù)組。那么對(duì)于每個(gè)新生成的a【i】,b【i】應(yīng)該有相應(yīng)的偏移。而對(duì)于b的某一項(xiàng)先-a【i】,后一項(xiàng)+a【i+1】,恰好能滿足前綴和。,
    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);
    }
    //更新b數(shù)組,使得b數(shù)組變成自己的前綴和數(shù)組
    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;
}
二、4.二維差分

矩陣a(ij)的差分矩陣是指這樣的矩陣:a(ij)中的項(xiàng)是差分矩陣前綴和。那么借助一維差分和二維前綴和的經(jīng)驗(yàn),我們知道可以這樣初始化差分矩陣b(假若要把陰影部分加上c)(這里我們不必考慮b的具體構(gòu)造):
在這里插入圖片描述
那么b應(yīng)該作相應(yīng)的變化:b(x1,y1)+= c,b(x2+1,y1)-= c,b(x1,y1+1)-= c ,b(x2+1,y2+1)+= c。為什么這樣修改以后a中陰影部分會(huì)+c呢?、因?yàn)閷?duì)于a數(shù)組,靠近往右往下方向是相加的b數(shù)組中的項(xiàng)增大的方向,那么我們只要給區(qū)域左上角的b(x1,y1)加上c,那么x1,y1以后的a中的項(xiàng)(即右下角的項(xiàng))都會(huì)加上c。然后在陰影之外我們不希望a中數(shù)據(jù)有變化,所以只要做相應(yīng)的調(diào)整即可。
在這里插入圖片描述

#includeusing namespace std;

const int N = 1010;

int n, m, q;
//a是原數(shù)組,b是差分?jǐn)?shù)組
int a[N][N], b[N][N];

void insert(int x1, int y1, int x2, int y2, int c)
{b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

int main()
{scanf("%d%d%d", &n, &m, &q);

    for (int i = 1; i<= n; i ++ )
        for (int j = 1; j<= m; j ++ )
            scanf("%d", &a[i][j]);

    for (int i = 1; i<= n; i ++ )
        for (int j = 1; j<= m; j ++ )
            insert(i, j, i, j, a[i][j]);

    while (q -- )
    {int x1, y1, x2, y2, c;
        cin >>x1 >>y1 >>x2 >>y2 >>c;
        insert(x1, y1, x2, y2, c);
    }

    for (int i = 1; i<= n; i ++ )
        for (int j = 1; j<= m; j ++ )
        //更新b,使得它作為自己的前綴和數(shù)組
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];

    for (int i = 1; i<= n; i ++ )
    {for (int j = 1; j<= m; j ++ ) printf("%d ", b[i][j]);
        printf("\n");
    }

    return 0;
}

好啦!以上便是本篇文章的全部?jī)?nèi)容。這里的代碼均出自Acwing閆學(xué)燦大佬之手,這是他的主頁(yè):
Acwing閆學(xué)燦
博主給代碼加上了注釋和自己的思考總結(jié)。祝大家學(xué)習(xí)愉快!

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


本文題目:XCPC歷險(xiǎn)記第二章!帶你玩轉(zhuǎn)高精度、前綴和與差分!-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://weahome.cn/article/ioose.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部