編程學習筆記---9月

08.28

1、最小公倍數(shù)LCM
求法:兩個數(shù)的乘積,除以他們的最大公因數(shù)。所以求最小公倍數(shù)實質上還是求最大公因數(shù)。

例題:求最小公倍數(shù)。
限制:正整數(shù) <= 1000
求解:(a*b) / gcd(a,b)

2、素數(shù)篩法
即:判斷一個數(shù)是否為素數(shù)。
方法:除到sqrt√n,看是否能整除。時間復雜度為O(√n)

技巧:

  • 先求出邊界 sqrt(n) + 1,保存在整數(shù)中,而不是在for循環(huán)中作為判斷條件。這樣只會計算一次。如果是在sqrt中,就會計算多次。
  • 如果計算一個數(shù)組中的數(shù)是不是素數(shù),可以單個判斷,但是這樣時間復雜度較高。做法:將一個素數(shù)的倍數(shù)都標記為非素數(shù)。

例題:找素數(shù)
限制:n<= 10000
代碼實現(xiàn):

初始化函數(shù),init()

mark[i]標記為false
primeSize為0

for(int i = 2; i<= 10000; i++){
    if(mark[i] == true) continue;
    prime[primeSize++] = i;  記錄素數(shù)
    
    for(int j = i*i; j<= 10000; j+= i){
        mark[j] = true;  標記倍數(shù)
    }
}

main函數(shù)中對于每次循環(huán)

bool isOutput = false;
用來進行標記。

技巧:

  • 在標記時,不必從2i開始標記,因為i*k已經(jīng)被k標記過了。我們從i^2開始標記即可。

3、分解素因數(shù)
比如:求正整數(shù)N的素因數(shù)的個數(shù)。

例題:
要求:求素因數(shù)。輸出有多少個素因數(shù)。
限制:N < 10^9
思路:首先利用素數(shù)篩法得到所有素數(shù)。輸入n后,依次遍歷所有素數(shù),判斷其是否是n的因數(shù)。

例題:求N的所有素因數(shù)的個數(shù)。
技巧:

  • 要求的是10^9,但是只用自己分解到√10^9即可,如果有大于這個數(shù)的不能分解,那么它一定是素因數(shù),并且只有一次。
  • 已知素因數(shù),求整因數(shù)個數(shù)


    image.png
image.png

例題:整除問題
要求:給定n,a求 最大的 k,使 n!可以?? a^k整除, ????但不能??被 a^(k+1)????整除。
限制:n <= 1000, a<= 1000

技巧:

  • 首先n!可能很大,不能直接求出數(shù)值再分解。
  • 求k的方法,只需要分解出素因數(shù)之后再進行比較冪的數(shù)值求k即可。

實現(xiàn)過程如下:

  • 按照之前的步驟,篩選范圍內(nèi)所有的素數(shù)。
  • 計數(shù)器清零。計數(shù)器記錄的是素因子對應的冪指數(shù)。cnt保存prime[]中對應的分解后的冪數(shù)。
for(int i = 0; i < primeSize; i++){
  cnt[i] = cnt2[i] = 0;
}
  • cnt的值計算如下
for(int i = 0; i < primeSize; i++){
    int t = n;
    while(t){
        cnt[i] += t/prime[i];
        t = t/prime[i];
    }
}
  • 對于比較小的a,可以直接分解素因數(shù)。
for(int i = 0; i< primeSize; i++){
    while(a%prime[i] == 0){
        cnt2[i]++ ;
        a/= primt[i];
    }
    
    if(cnt2[i] == 0) continue;
    
    if(cnt[i] / cnt2[i] < ans){
        ans = cnt[i] / cnt2[i];
    }
}

4、二分求冪
將指數(shù)進行分解即求其二進制。任何高次冪都可以用這種方法

例題:人見人愛A^B
限制:A,B <=10000
要求:求后三位的結果。所以就不用保存整體的,只用保存A和B分別后三位即可。

08.29

1、高精度整數(shù)
對于特別大的整數(shù),需要用一個結構體來保存高精度整數(shù)

struct bigInteger{
    int digit[1000];
    int size;
};

例題:計算a+b
要求:a和b的位數(shù)不超過1000位
代碼實現(xiàn)如下:
頭文件:

#include <stdio.h>
#include <string.h>

set(),把str轉化為數(shù)字,并保存在digit[]中。

int L = strlen(str);
for(int i = L - 1, j = 0, t = 0, c = 1; i>= 0; i--){
    t += (str[i] - '0'*c);
    j++;
    c*= 10;
    
    if(j==4 || i == 0){
        digit[size++] = t;
        j = 0;
        t = 0;
        c = 1;
    }
    
}

output輸出 printf("%04d",digit[i]);,前置位可能需要補零。

因為是自己定義的數(shù)組,需要重載+運算符

bigInteger operator + (const bigInteger &A) const {
    
    bigInteger ret;
    ret.init();
    
    int carry;
    for(int i = 0; i < A.size || i < size; i++){
        int tmp = A.digit[i] + digit[i] + carry;
        carry = tmp / 10000;
        tmp %= 10000;
        ret.digit[ret.size++] = tmp;
    }
    
    if(carry != 0){
        ret.digit[ret.size++] = carry;
    }
    
    return ret;
}

2、高精度乘法
一般是一個高精度整數(shù)??一個普通的整數(shù)。

例題:輸出階乘
限制:N <= 1000

代碼實現(xiàn)如下:
對于set(),如果原本的x不大,可以直接操作賦值到digit中,不用由str[]轉過來那么麻煩。

void set(int x){
    init();
    do{
        digit[size++] = x % 10000;
        x/= 10000;
    }while(x != 0);
}

重載*運算符

bigInteger operator * (const int x) const {
    
    bigInteger ret;
    ret.init();
    
    int carry = 0;
    for(int i = 0; i < size; i++){
        int tmp = x * digit[i] + carry;
        carry = tmp / 10000;
        tmp %= 10000;
        ret.digit[ret.size++] = tmp;
    }
    
    if(carry != 0){
        ret.digit[ret.size++] = carry;
    }
    
    return ret;
}

3、綜合例題:進制轉換
要求:將 M 進??的數(shù) X ????轉換為 N 進制??的數(shù)??出。
限制:M,N <= 36, 輸出時小寫,且有大數(shù)據(jù)。
知識點:高精度需要進行:
高??精??數(shù)與普通整數(shù)????????求積,????求商,求模
高精數(shù)與高精數(shù)求和

代碼實現(xiàn)如下
頭文件

#include <stdio.h>
#include <string.h>

加法和乘法和上面類似,下面重點看 / 和%

bigInteger operator / (int x) const {
    
    bigInteger ret;
    ret.init();
    
    int remainder = 0;
    
    for(int i = size - 1; i>= 0; i--){
        int t = (remainder*10000 + digit[i])/x;
        int r = (remainder*10000 + digit[i])%x;
        
        ret.digit[i] = t;
        remainder = r;
        
    }  修改digit[i]的值。
    
    ret.size = 0;
    for(int i = 0; i< maxDigits; i++){
        if(digit[i] != 0) ret.size = i;
    }
    ret.size ++;  修改size的值為相應的結果。
    
    return ret;
}

%運算如下

int operator % (int x) const{
    int remainder = 0;
    for(int i = size - 1; i>= 0; i--){
        int t = (remainder*10000 + digit[i])/x;
        int r = (remainder*10000 + digit[i])%x;
        remainder = r;
    }
    
    return remainder;
}

本題結束,難度還是比較大的。

補充:如果求一個高精度的整數(shù)除以一個比較小的數(shù)后的余數(shù),可以用如下代碼

int ans = 0;
for(int i = 0; str[i]; i++){
    
    ans *= 10;
    ans += str[i] - '0';
    ans %= mod;
}

這個實際上就是除法的運算方法。

注意:高精度運算有時時間復雜度比較高,在估算時間復雜度時不能忽略這個。

4、map
功能是:將一個類型的變量映射為另一個類型
例題:產(chǎn)生冠軍
要求:判斷能否產(chǎn)生冠軍,輸出yes 或 no即可
知識點:拓撲排序,生成有向圖。如果有結點入度為0并且這個節(jié)點唯一,說明是YES!/ 將選手的姓名映射為節(jié)點編號,需要標準對象map

代碼實現(xiàn)如下:
對于每個測試用例(while中的)
初始化

for(int i = 0 ; i < 2*n; i++){
    in[i] = 0;
}

M清空
M.clear();

對輸入的進行在in[]中修改。

for(int i = 0; i<n; i++){. 要輸入n組
    char str1[50],str2[50];
    scanf("%s%s",str1,str2);
    string a = str1,b = str2;
    
    int idxa,idxb;
    if(M.find(a) == M.end()){
        idxa = idx;  idx是下一個要分配的數(shù)字
        M[a] = idx++;
    }
    else idxa = M[a];
    
    if(M.find(b) == M.end()){
        idxb = idx;
        M[b] = idx++;
    }
    else idxb = M[b];
    
    這里是找到了idxa和idxb
    in[idxb]++;
}

輸入完之后,統(tǒng)計所有節(jié)點的入度,看看入度為0的節(jié)點的個數(shù)是不是1即可。

int cnt = 0;

for(int i = 0; i < idx; i++){
    if(in[i] == 0) cnt++;
}

puts(cnt == 1? "YES" : "NO");

注意:
使用map,需要包含頭文件 需要包含 map<string,int> M;
map的內(nèi)部實現(xiàn)是紅黑樹。

5、滾動數(shù)組
作用:完成常數(shù)量優(yōu)化和 減少代碼量。
對于循環(huán)賦值操作,可以使用滾動數(shù)組來進行優(yōu)化

說白了就是,之前的結果不再需要了,那么我可以只使用少數(shù)幾個數(shù)組,每次分別保存在某個數(shù)組中,下一次再保存在另外一個數(shù)組中。

6、小技巧

  • 可以將mod2運算改為位運算,將/2運算改為 >> 1,即右移1
  • cin比scanf耗時多很多。輸入外掛可以在scanf的基礎上再次優(yōu)化。(了解一下即可,估計我也用不上)
  • 流氓剪枝:強行剪去我覺得不是答案的結果。
  • 不要在程序中混用printf和cout,因為他們的輸出機理不同,混用可能會造成不可預見的后果。

7、排版
根據(jù)題目示例來找規(guī)律。
例子:


屏幕快照 2020-08-25 下午5.00.27.png

代碼實現(xiàn)如下:

#include <stdio.h>

int main(){
    int h;  輸入h
    while(scanf("%d",&h) != EOF){
        int maxline = h + (h-1)*2;
        for(int i = 1; i<= h; i++){  外面的,表示一共輸出幾行,每次循環(huán)是一行
            for(int j = 1; j <= maxline; j++){  每行都要輸出maxline個字符,但是有的是* ,有的是前面的空格。
                if(j < maxline - h - (i-1)*2 + 1){
                    printf(" ");
                }
                else
                    printf("*");
            }


            printf("\n");
        } // end for-i 說明輸出一行結束。

    } //end while
    return 0;
}

這個規(guī)律性比較強,對于規(guī)律性不強的,要先完成排版,再進行輸出。
例子:疊筐
不太容易直接輸出,就自己先進行排序。
限制:總的輸出邊長大小 n <= 80

思路:每次確定圈中內(nèi)容時:都是先找到左上角的點。
代碼實現(xiàn)如下:

#include <stdio.h>

int main(){
    int outPutBuf[82][82];
    char a,b;
    int n;
    bool firstCase = true;
    
    while(scanf("%d %c %c",&n,&a,&b) == 3){
        
        if(firstCase == true){
            firstCase = false;
        }
        else
            printf("\n");  由于每次新輸出都需要換行,但是第一次不需要換行,最后一次輸出之后不需要換行,所以進行這個判斷,只有第一行不用換行,其他都需要換行。
        
        for(int i = 1,j = 1; i<= n; i+= 2,j++){ i<=n是因為要輸出n行,i可以看作是邊長。最開始變長是1,j用來計數(shù),看是第幾次輸出。
            int x = n/2 + 1, y = x;  找到最中心的節(jié)點
            x = x - (j-1);
            y = y - (j-1); //左上角的點
            char c = j % 2 == 1? a:b;   要填充的字符是哪個
            
            for(int k = 1; k <= i; k++){  i是最終的變長,k是開始一點一點輸出。
                outPutBuf[x + k - 1][y] = c;
                outPutBuf[x][y + k - 1] = c;
                outPutBuf[x + i - 1][y + k - 1] = c;
                outPutBuf[x + k - 1][y + i - 1] = c;
            } 保存完了

        }
        
        if(n!= 1){ 如果n = 1,只用輸出一個,也沒這么多情況了。
            outPutBuf[1][1] = ' ';
            outPutBuf[n][1] = ' ';
            outPutBuf[1][n] = ' ';
            outPutBuf[n][n] = ' ';
        }
        
        for(int i = 1; i <= n; i++){
            for(int j = 1; i<= n; j++){
                printf("%c",outPutBuf[i][j]);
            }
            printf("\n");
        }
    }

    return 0;
}

8、貪心算法
思想:總是選擇當前最好的選擇

例題:
房子有N個房間,每個房間含的javabean的重量包含在J[i]中,需要的貓糧是F[i],如果給的貓糧是F[i] * a%,得到的Javabean也是J[i]*a%.
限制:所有的整數(shù) <= 1000。輸出要限制到小數(shù)點后三位。

思想:每次都買性價比最高的東西。

代碼實現(xiàn)如下:

商品的結構體的實現(xiàn)如下

struct goods{
    double j;
    double f;
    double s;
    
    bool operator < (const goods &A) const{
        return s > A.s;
    }
}

可以看成包含成本f、收益j,s是j/f,并且重載 < 運算符。這樣就會按照性價比降序排列??吹氖?code>return s > A.s

main函數(shù)實現(xiàn)如下

int idx = 0;
double ans = 0;

while(idx < n && m > 0){
    
    if(m > buf[idx].f){  錢沒花完,我還能買
        ans += buf[idx].j;
        m -= buf[idx].f;
    }
    else{
        ans += buf[idx].j * m / buf[idx].f;  沒錢了
        m = 0;
    }
    idx ++;
}

貪心算法例題2:
要求:已知節(jié)目的時間表,如何看盡可能多的完整的節(jié)目
限制:節(jié)目數(shù)n <= 100.
思想:貪心算法

第一個節(jié)目優(yōu)先選擇結束時間最早的,后面的選擇 在觀看完這個節(jié)目之后,仍然可以完整觀看的節(jié)目中,結束最早的那個。

int currentTime = 0,ans = 0;

for(int i = 0; i < n; i++){
    if(currentTime <= buf[i].startTime){
        currentTime = buf[i].endTime;
        ans ++;
    }
}
printf("%d\n",ans);

要保證完整地看,需要currentTime <= buf[i].startTime
可以看出,思想還是比較簡單的。但是如果想出難的話還是很難的。

至此,第二章及以后的所有章節(jié)均看完!撒花!機試水平有了從0到0.001的提升!

還需要考慮的一個很重要的內(nèi)容是:時間復雜度的估計。
對于限制1秒,我們不能超過百萬級別,即不能超過1000萬。

完結撒花!并且九度OJ是不能再用的,??途W(wǎng)或PAT均可。

PAT (Advanced Level) Practice

08.30

1、A+B Format
要求:輸出a+b,多位數(shù)字要以,分割
限制: 10 ^(-6)<a , b < 10^6 / 只輸入一組數(shù)據(jù)

難點:如何輸出逗號
參考別人的答案,還是把整型數(shù)字轉為字符串

代碼實現(xiàn)如下:

#include <stdio.h>

char sumchar[10];  保存數(shù)組

void change(int number){ 把數(shù)字轉為字符型
    
    int index = 0, times = 0; index是在數(shù)組中的下標,times是數(shù)字的位數(shù)
    while(number != 0){
        
        if(times % 3 == 0 && times != 0){
            sumchar[index++] = ',';  加上逗號
        }
        
        sumchar[index++] = number % 10 + '0';  數(shù)字
        number /= 10;
        times = times+1; 是數(shù)字,位數(shù)加1
        
    }
}

int main(){
    
    int a,b = 0;
    int sum,i = 0 , end_index = 0;
    scanf("%d %d",&a,&b);
    sum = a+b;
    
    if(sum < 0){
        printf("-");
        sum = -sum;
    }
    
    change(sum); //這里不太合適,沒有考慮0的情況
    
    for(i = 0; sumchar[i] != 0 && i <= 10; i++){
        end_index = i;  找到末尾的數(shù)字
    }
    
    for(i = end_index; i>= 0; i--){
        printf("%c", sumchar[i]);  倒序輸出
    }
    
    return 0;
}

這個有一個極端的用例會出錯。

參考別人的代碼實現(xiàn),發(fā)現(xiàn)少了結果是0的情況。如果是0,就不會輸出任何東西。

有挺多細節(jié)需要考慮,突然想到需要倒序輸出,是一個后進先出的例子,如果熟練的話可以用棧來實現(xiàn)。

08.31

1、KY2:查找和排序
要求:成績按照從低到高和從高到低分別排序、輸出
限制:無
知識點:排序

卡在:忘記如何對結構體中的變量進行排序了。

參考代碼,分別對兩種排序用兩個函數(shù)實現(xiàn)。輸出方法也用一個函數(shù)來實現(xiàn)了。排序它內(nèi)部是使用冒泡排序來完成的。

收獲:

  • struct前面要加typedef
  • 定義數(shù)組長度時,大小最好不要弄成變量n,可以設一個較大的絕對不會超過的數(shù)。
  • 字符串和整型數(shù)字是可以在同一個scanf中輸入的,scanf("%s %d",a,&b) 即可

但是感覺這種還是比較復雜的,如果可以使用sort()來進行排序,就很簡單了。

參考sor()的代碼,結構體排序的方法是重新寫一個排序函數(shù)。如下

bool cmp0(Stu a,Stu b){
    if(a.score!=b.score){
        return a.score>b.score;
    }else{
        return a.num<b.num;
    }
}

這個是降序排列,如果成績相等,num小的排在前面

if(temp==1){
            std::sort(stu,stu+n,cmp1);
        }
        else if(temp==0){
            std::sort(stu,stu+n,cmp0);
        }

如下語句即可完成sort()的調用。

2、求約數(shù)的個數(shù)
限制:個數(shù)n<=1000,每個數(shù)字的大小Num<=1000000000
知識點:對大數(shù)據(jù)的處理

卡在:這么大的數(shù)據(jù)如何表示

別人代碼實現(xiàn)如下:

i*i<num的形式,數(shù)值穩(wěn)定性更好,比sqrt()好
#include<iostream>
using namespace std;
int numOfDivisor(int num)
{
    int ans = 0;
    int i;
    for (i = 1; i*i<num; i++)  遍歷所有小于根號下的數(shù)
    {
        if (num%i == 0)
            ans += 2;   這里一大一小兩個數(shù)
    }
    if (i*i == num) ans++; 正好中間,就+1
    return ans;
}
int main()
{
    int n, num;
    while (cin >> n)
    {
        for (int i = 0; i<n; i++)
        {
            cin >> num;
            cout << numOfDivisor(num) << endl;
        }
    }
    return 0;
}

輸入輸出在main函數(shù)中,求約數(shù)是在numDivisor函數(shù)中。

這個是最簡單的方法,但是耗時也比較大。

還可以用 質數(shù)篩法,篩選出所有的質數(shù)。(但是這有什么用呢?)有用:如果是質數(shù),就不用再往下判斷它有沒有因子了,它除了1和它本身,沒有其他約數(shù)了就。

/*
 * 因數(shù)個數(shù)(使用到質數(shù)篩法)
 */
#include <iostream>
#include <cstdio>
#include <vector>
#include <math.h>

using namespace std;

const int MAXN = 4e4;

bool isPrime[MAXN];                 //標記數(shù)組
vector<int> prime;                  //保存質數(shù)

void initial(){                     //初始化
    fill(isPrime,isPrime+MAXN,true);
    isPrime[0]=false;
    isPrime[1]=false;
    for(int i = 2;i<MAXN;i++){
        if(!isPrime[i]){            //非質數(shù),則跳過該數(shù)
            continue;
        }
        prime.push_back(i);
        for(int j = i+i;j<MAXN;j+=i){
            isPrime[j]=false;       //質數(shù)的倍數(shù)為非質數(shù)
        }
    }
    return;
}

int fun(int n){
    vector<int> exponent;

    for(int i = 0;i<prime.size();i++){
        int factor = prime[i];
        if(n<factor){
            break;
        }
        if(n%factor == 0){
            int num = 0;
            while(n%factor == 0){
                n = n/factor;
                num++;
            }
            exponent.push_back(num);
        }
    }

    if(n>1){
        exponent.push_back(1);
    }

    int ans = 1;
    for(int i = 0;i<exponent.size();i++){
        ans*=exponent[i]+1;
    }

    return ans;
}

int main(){
    initial();
    int m;
    while(scanf("%d",&m)!=EOF){
        if(m == 0){
            break;
        }
        for(int i = 0;i<m;i++){
            int n;
            scanf("%d",&n);
            printf("%d\n",fun(n));
        }
    }
    return 0;
}

初始化其實就是素數(shù)篩法,找出所有的質數(shù)。
fun()就是求因數(shù)的函數(shù)。

變量:
vector exp
prime里面放的是所有素數(shù)

對每一個素數(shù),分別進行如下操作
factor是當前素數(shù)
如果n還可以分解為這個素數(shù),統(tǒng)計出現(xiàn)了多少次這個素數(shù),記在exp棧里面。同時n也除去相應的數(shù)。

最終的個數(shù)根據(jù)之前的一個公式來計算:
(e1+1)(e2+1)(e3+1)....(en+1)

  • vector除了可以用來當棧操作,在不使用棧的特性時,也可以單純地用來計數(shù)。

09.01

1、A + B 的多項式形式
限制:K <= 10, N(指數(shù)) <= 1000
考察:直接用數(shù)組記錄即可。(位置表示索引,有點類似哈希)

不要一不會就看答案!多思考!思考是進步的過程!?。?/p>

09.03

1、多項式相加

  • 對于double型,判斷是否為0,最好考慮誤差
  • C++中,abs要使用頭文件cmath,C中使用stdlib.h

輸出錯誤,應該倒序輸出


image.png

現(xiàn)在的問題在 double型系數(shù)不能正確讀取,剛才不知道為什么錯了,重新改為scanf("%lf",&xishu),即可。

自己代碼實現(xiàn)

#include <iostream>
#include <cmath>

using namespace std;

double A[11] = {0},B[11] = {0},ans[11] = {0};

int main(){
    
    int Ka,Kb,i;
    scanf("%d",&Ka);
    
    int count_num = 0;
    int index;
    double xishu;
    
    while(Ka--){
        scanf("%d %lf",&index, &xishu);
        A[index] = xishu;
    }
    
    scanf("%d",&Kb);
    while(Kb--){
        scanf("%d %lf",&index, &xishu);
        B[index] = xishu;
    }
        
    for(i = 0; i<= 11; i++){
        ans[i] = A[i] + B[i];
        if( abs(ans[i] - 0) >= 0.00000001){
            count_num ++;
        }
    }
    
    printf("%d",count_num);
    
    for(i = 11; i >= 0; i--){
        if(abs(ans[i] - 0) >= 0.00000001)
            printf(" %d %l.1f",i,ans[i]);
    }
    
    return 0;
}

其實自己弄的復雜了,并且答案還不對。

K是數(shù)字的個數(shù),但是n才是系數(shù)的個數(shù),所以數(shù)組的大小應為N的個數(shù)。

還是不知道自己哪里錯了,參考別人的代碼

#include<stdio.h>

const int max_n = 1111;
double a[max_n] = {};  只用一個來實現(xiàn)就夠了
int main(){
  
  int k, n, count = 0;
  double e;
  scanf("%d", &k);
  for(int i = 0; i < k; i ++){
    scanf("%d%lf", &n, &e);
    a[n] = e;
  }
  
  scanf("%d", &k);//這里k只是為了存儲,所以這兒k是可以重復存放值。
  for(int i = 0; i < k; i ++){
    scanf("%d%lf", &n, &e);
    a[n] += e;//這兒其實就是有相同的就相加,沒有相同的就不想加
  }
  
  for(int i = 0; i < max_n; i ++){
    if(a[i] != 0){
      count ++;
    }
  }
  printf("%d", count);
  for(int i = max_n - 1; i >=0; i --){
    if(a[i] != 0) printf(" %d %.1f", i, a[i]);
  }
  return 0;
}

2、Emergency
題目:給出圖,找出最短路徑。
限制:N(節(jié)點數(shù))<500
知識點:印象中,圖論用鄰接矩陣實現(xiàn)
小細節(jié):最后沒空格

參考答案1

需要用到Dijkstra 算法。
設置內(nèi)存,頭文件#include <memory.h>


image.png

fill函數(shù),可以設定為任意指定的值,頭函數(shù)<algorithm>

代碼實現(xiàn)過程
1、定義變量,初始化

2、Dijk算法{
找出最小的頂點,標記這個頂點已經(jīng)計算過了

有兩種情況會替換掉原來的值

}
不懂Dijkstra算法為什么有個沒有用到的i的for循環(huán)

3、Counting Leaves
題目:
限制:N節(jié)點數(shù)量 < 100,M 非葉子結點的數(shù)量
知識點:考察??的定義和層次遍歷

參考別人代碼,可以用dfs,也可以用bfs.
dfs實現(xiàn)如下

頭文件
#include<iostream>
#include<vector>
#include<algorithm> 后面有一個max()函數(shù),所以需要algorithm頭文件
using namespace std;

定義變量
vector<int> v[100];
int book[100];
int maxDepth=-1; 

void dfs(int index,int depth){
    // 此時第index結點已經(jīng)沒有子結點了,則表明是葉子結點 
    if(v[index].size()==0){
        // 統(tǒng)計該葉子結點 
        book[depth]++;
        // 更新最大層次 
        maxDepth = max(maxDepth,depth);
        return ;
    }
    // 遞歸調用 
    for(int i=0;i<v[index].size();i++){
        dfs(v[index].at(i),depth+1);
    }
} 

int main(){
    int N,M;
    int node,K;

    while(cin>>N>>M){
        for(int i=0;i<M;i++){
            cin>>node>>K;
            for(int j=0;j<K;j++){
                int temp;
                cin>>temp;
                v[node].push_back(temp);  把子樹的信息輸入到v中
            }
        }
    
        // 從第一個結點開始,第零層 
        dfs(1,0);
        
        cout<<book[0];
        for(int i=1;i<=maxDepth;i++){
            cout<<" "<<book[i];
        } 
    
  } end while
    return 0;

}

還可以使用bfs,不同的是,需要額外的數(shù)組來統(tǒng)計每個節(jié)點所在的層次

邏輯搞懂了其實也不難

4、Spell It Right
題目:求和,字母輸出
限制:N(數(shù)字) < 10的100次方
知識點:大數(shù)存儲,每個數(shù)字轉換為一個字母,數(shù)組實現(xiàn)

一道挺簡單的題,編譯還是有很多錯。
首先字母表的定義


8AC9976D-F3F3-4851-B866-9760EE89F209.png

vector不是pop,是pop_back()

原來的結果錯誤,是因為少了一層digit嵌套。

測試結果發(fā)現(xiàn)還有一個段錯誤,是沒有考慮到輸出為0的情況,加入為0的情況就正確啦!我人生的第一個AC!!


53EAD403-B5A6-40F2-BF55-D5A951E181B4.png

代碼實現(xiàn)如下

#include <iostream>
#include <vector>
using namespace std;

char num[110];
char zimubiao[10][10] = {"zero","one","two","three","four","five","six","seven","eight","nine"};

int main(){
    int i;
    int ans = 0,flag = 0;
    scanf("%s",num);
    for(i = 0; num[i]!= 0 && i < 110; i++){
        ans += num[i] - '0';
    }
    
    vector<int> digit;
    flag = ans;
    while(ans != 0){
        digit.push_back(ans%10);
        ans /= 10;
    }
    if(flag != 0){
        printf("%s",zimubiao[digit[digit.size()-1]]);
        digit.pop_back();
    }
    else{
        printf("%s",zimubiao[0]);
    }
    
    while(digit.size()!= 0){
        printf(" %s",zimubiao[digit[digit.size()-1]]);
        digit.pop_back();
    }
    
    return 0;
}

也可以用數(shù)組實現(xiàn),只計算一個數(shù)組有效長度即可。

5、Sign In and Sign Out
題目:簽到簽退,要求找出最早和最晚時間。
限制:ID_number字符串字符 < 15
知識點:對時間格式的數(shù)據(jù)進行操作的能力

輸入的時候 scanf("%s %d:%d:%d %d:%d:%d",ID,&H1,&M1,&S1,&H2,&M2,&S2);,這樣輸入。
比較的時候,都化為秒數(shù)去比較。

收獲:

  • 不用所有數(shù)據(jù)都記錄,只記錄最開始和最后的數(shù)據(jù)即可,每次輸入之后都進行比較。

  • 字符串賦值的時候,先清空,再賦值 strcpy(in,"");strcpy(in,ID);

  • 輸出:printf("%s %s",in,out);

6、Maximum Subsequence Sum
題目:最長子序列
知識點:動態(tài)規(guī)劃
限制:數(shù)量K <= 10000,如果都是負數(shù),需要特殊處理

j表示以j結尾
變化的過程:dp[i][j] = dp[i][j-1] + v, (?). dp[i]=max(dp[i],dp[i-1]+a[i])

代碼實現(xiàn)如下:

#include<iostream>
#include<cstdio>
using namespace std;
int a[10005],l[10005],r[10005];
int dp[10005];//以a[i]結尾的最大連續(xù)區(qū)間和
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        dp[i]=a[i];//初始化
    } 首先把dp初始化了,所以后面比較的時候就可以拿dp的值比較.

    l[0]=r[0]=0;

    for(int i=1;i<n;i++)
    {
        if(dp[i-1]+a[i]>=dp[i])//如果a[i]>=0,且數(shù)值變大了
        {
            dp[i]=dp[i-1]+a[i];
            l[i]=l[i-1];//區(qū)間左端點不變,右端點更新
            r[i]=i;
        }
        else//如果a[i]是負數(shù),新建一個區(qū)間
        {
            l[i]=i;
            r[i]=i;
        }
    }
    int ans=-1,pos=0,flag=0;
    for(int i=0;i<n;i++)
    {
        if(dp[i]>ans)
        {
            flag=1;
            ans=dp[i];
            pos=i;
        }
    }
    //cout<<flag<<endl;
    if(flag==0)
        cout<<0<<' '<<a[0]<<' '<<a[n-1]<<endl;
    else
        cout<<ans<<' '<<a[l[pos]]<<' '<<a[r[pos]]<<endl;
    return 0;
}

也可以用模擬的方法

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<map>
#define MAX 1000000
#define ll long long
using namespace std;
int a[10005];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int ans=-1,l=0,r=n-1;
    int temp=0,first=0;
    for(int i=0;i<n;i++)
    {
        temp=temp+a[i];
        if(temp<0)
        {
            temp=0;
            first=i+1;
        }
        else if(temp>ans)
        {
            ans=temp;
            l=first;
            r=i;
        }
    }
    if(ans<0)
        ans=0;
    cout<<ans<<' '<<a[l]<<' '<<a[r]<<endl;
    return 0;
}

思想是:每次都加上一個試試,有最好的結果(更新ans),一般的結果(什么也不做)和最差的結果(歸0)。

7、Elevator
題意:電梯升降,計算時間。
限制:所有數(shù) < 100

沒有難度,數(shù)組計算和之前的差即可。但是答案都錯啦?
因為:1沒有print 2 i改為下標從1開始之后,沒有 <= n

更改之后代碼如下:

#include <iostream>
#include <algorithm>
using namespace std;

int main(){
    int n, a[110],diff[110],i;
    int ans = 0;
    scanf("%d",&n);
    
    a[0] = 0;
    for(i = 1; i<= n; i++){
        scanf("%d",&a[i]);
        diff[i] = a[i] - a[i-1];
    }
    
    for(i = 1; i <= n; i++){
        if(diff[i] >= 0){
            ans += (diff[i]*6) + 5;
        }
        else
            ans += (-diff[i]*4) + 5;
    }
    
    printf("%d",ans);
    
    return 0;
}

8、Product of Polynomials
題意:多項式相乘
知識點:仍然是數(shù)組的操作
限制: K <= 10,N <= 1000

實現(xiàn):指數(shù)相加,系數(shù)相乘

在調試發(fā)現(xiàn)輸入的方法不對,導致數(shù)據(jù)篡位


017EADA6-2D40-42F4-A6AD-9A063BF63532.png

初次代碼實現(xiàn):(有錯)

#include <iostream>
#include <algorithm>
#include <cmath>

double A[1100] = {0},B[1100] = {0},ans[2200] = {0};
int Ka,Kb,N,count = 0;

int main(){
    
    int i = 0, j= 0;
    scanf("%d",&Ka);
    for(i = 1; i<= Ka; i++){
        scanf("%d%lf",&N,&A[N]);
    }
    scanf("%d",&Kb);
    for(i = 1; i<= Kb; i++){
        scanf("%d %lf",&N,&B[N]);
    }
    
    for(j = 1; j <= 1100; j++){
        for(i = 1; i<= 1100; i++){
            ans[i+j] += B[i]*A[j];
        }
    }
    
    for(i = 0; i<= 2200; i++){
        if(ans[i] != 0) count++;
    }
    printf("%d",count);
    for(i = 2200; i>= 0; i--){
        if(abs(ans[i]) > 1e-5) printf("%d %l.1f",i,ans[i]);
    }
    return 0;
}

錯誤:

  • 應該先輸入N,再輸入系數(shù),即給數(shù)組矩陣賦值,與確定數(shù)組的坐標,不能在同一條語句中。
  • for循環(huán)計算ans時,這時候算的是系數(shù),從0開始。而K輸入時,需要的是K次,若從1開始也沒關系,只用計數(shù)即可。

09.04

1、A*B 多項式相乘
測試用例正確的,但是提交,答案還是錯誤.
為什么還是錯的,我要瘋了。

參考別人答案

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
    double A[1020]={0.0};
    double B[1020]={0.0};
    double C[2020]={0.0};
    int ka,kb;
    cin>>ka;
    for(int i = 0;i<ka;i++)
    {
        int nk;
        double a;
        cin>>nk>>a;
        A[nk] = a;
    }
    cin>>kb;
    for(int i = 0;i<kb;i++)
    {
        int nk;
        double a;
        cin>>nk>>a;
        B[nk] = a;
    }
    for(int i=0;i<=1000;i++)
        for(int j=0;j<=1000;j++)
        {
            C[i+j]+=A[i]*B[j];
        }
    int count = 0;
    for(int i=0;i<=2000;i++)
        if(C[i]!=0.0)
            count++;
    cout<<count;
    for(int i = 2000;i>=0;i--)
        if(C[i]!=0.0){
            cout<<" "<<i<<" ";
            printf("%.1lf",C[i]);
        }
    return 0;
}

把scanf 都換位 cout等,就有部分錯誤了
把最后輸出換為printf("%.1lf",ans[i])

部分正確。

還是不知道為什么錯,先不管了。

2、Radix
題目:進制轉換
限制:N不超過10個數(shù)字,
難點:怎么確定進制?要一個一個去試嗎?試到最大結束?
參考結果:雖然思路可以,但是超時

可以用二分法來確定
基數(shù)的最小值:N2的最大權值 + 1
基數(shù)的最大值:N1 + 1

mx用于計算N2的最大權值

真正二分的過程用while來實現(xiàn)

while(l <= r){

  ......
  如果偏大
  if(tmp > num1 || tmp < 0)
    r = mid - 1;
  else if(tmp < num1) {
    l = mid + 1;
    }
  else{
    cout << mid;
    return 0;
}

}

收獲1:

  • 該用頭文件 #include <bits/stdc++.h> 萬能頭文件
  • 進制可能是很大的,用longlong型
  • 一個非常巧妙的進制轉換的方法
for(int i=0;i<len1;++i){
12         num1*=rad;  每次都這樣,最前面的數(shù)肯定乘的多。
13         if(s1[i]>='0'&&s1[i]<='9')
14             num1+=s1[i]-'0';
15         else
16             num1+=s1[i]-'a'+10;
17     }

3、World Cup Betting
計算、輸出題
每一場都選最大的即可

開心!第一次無改錯直接編譯通過且答案完全正確??!

#include <bits/stdc++.h>
using namespace std;

double peilv[4][4];  存放賠率
double ans = 0;  最后結果
char c[3];  存放標志 WTL
int i = 1,j = 1;

int main(){
    
    for(i = 1; i <= 3; i++){
            
        cin >> peilv[i][j] >> peilv[i][j+1] >> peilv[i][j+2]; 
            
        peilv[i][0] = max(max(peilv[i][j],peilv[i][j+1]),peilv[i][j+2]);
            
        if (peilv[i][0] == peilv[i][j]) c[i-1] = 'W';
        if (peilv[i][0] == peilv[i][j+1]) c[i-1] = 'T';
        if (peilv[i][0] == peilv[i][j+2]) c[i-1] = 'L';
    }
    
    ans = (peilv[1][0]*peilv[2][0]*peilv[3][0]*0.65 - 1)*2;
    
    cout << c[0] << " " << c[1] << " " << c[2] << " " << ans;
    
    return 0;
}

4、 The Best Rank
題意:找出每個學生最好的排名
限制:N和M < 2000
考察:對數(shù)組的操作
思路: A C M E 四門課的N成績,分別sort排序,結果保存在數(shù)組中。
查詢的M個人,分別按順序招,輸出排名最靠前的。

我想到的是單純用數(shù)組存儲,參考別人,結構體存儲更簡便。

代碼如下

#include <cstdio>
#include <algorithm>
using namespace std;
struct node {
  int id, best;
  int score[4], rank[4];
 }stu[2005];
int exist[1000000], flag = -1;
bool cmp1(node a, node b) {
     return a.score[flag] > b.score[flag];
}
int main(void ){
    int n, m, id;
    scanf("%d %d", &n, &m);
    for(int i = 0; i < n; i++) {
        scanf("%d %d %d %d", &stu[i].id, &stu[i].score[1], &stu[i].score[2], &stu[i].score[3]);
        stu[i].score[0] = (stu[i].score[1] + stu[i].score[2] + stu[i].score[3]) / 3.0 + 0.5;
    }
    for( flag = 0; flag <= 3; flag++) {
        sort(stu, stu + n, cmp1);
        stu[0].rank[flag] = 1;
        for(int i = 1; i < n; i++) {
             stu[i].rank[flag] = i + 1;
             if( stu[i].score[flag] == stu[i-1].score[flag] )
                         stu[i].rank[flag] = stu[i-1].rank[flag];
        }
    }
    
    for( int i = 0; i < n; i++) {
         exist[stu[i].id] = i + 1;
         stu[i].best = 0;
         int minn = stu[i].rank[0];
         for( int j = 1; j <= 3; j++) {
              if( stu[i].rank[j] < minn) {
                  minn = stu[i].rank[j];
                  stu[i].best = j;
               }
           }
    }
    
    char c[5] = {'A', 'C', 'M', 'E'};
    for( int i = 0; i < m; i++) {
         scanf("%d", &id);
         int temp = exist[id];
         if( temp ) {
             int best = stu[temp-1].best;
             printf("%d %c\n", stu[temp-1].rank[best], c[best]);
         } else {
                  printf("N/A\n");
         }
    }
    return 0;
}

5、Battle Over Cities
之前做過
限制:N城市數(shù)目 < 1000,

其實就是利用深度遍歷,根據(jù)一個點,把其相鄰的所有點都遍歷一遍。

6、Waiting in Line

知識點:考察隊列、時間 操作

每過一分鐘,進行一次操作

#include <iostream>
#include <queue>
using namespace std;

struct Peo{
    int time, constTime, leaveTime, ind;
}p[1001];
queue<Peo> q[21];

int main(int argc, char const *argv[])
{
    int N, M, K, Q;
    cin >> N >> M >> K >> Q;
    for (int i = 1; i <= K; ++i){
        cin >> p[i].time;
        p[i].ind = i;
        p[i].constTime = p[i].time;
    }
    
    int index = 1, cnt = 1;
    for (int i = 1; i <= 10000; ++i){
        
        
        while(cnt <= N*M && index<=K){
            for (int j = 1; j <= N; ++j){
                if(q[j].size()<M) {
                    q[j].push(p[index++]);
                    cnt++;
                }
            }
        }
        
        
        
        for (int j = 1; j <= N; ++j){
            int ind = q[j].front().ind;
            p[ind].time--;
            if(p[ind].time==0){
                p[ind].leaveTime = i;
                q[j].pop();
                cnt--;
            }
        }
        
    }
    
    
    for (int i = 0; i < Q; ++i){
        int num; cin >> num;
        if(p[num].leaveTime-p[num].constTime<540) 
            printf("%02d:%02d\n", (p[num].leaveTime+480)/60, (p[num].leaveTime+480)%60);
        else printf("Sorry\n");
    }
    return 0;
}

7、Reversible Primes
題目:素數(shù)倒過來也是可逆的
限制:數(shù)字N < 10^5 進制D <= 10

寫代碼:6:53 - 7:10

簡單地改錯之后,運行超時了。


image.png

再改之后,還是答案錯誤.
疑問:23 ,2這個數(shù)組
理解錯題意了。

先把23轉為二進制,再反過來,再轉為10進制,再算是否為素數(shù)。

自己寫的代碼如下:

#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
using namespace std;

char kaishi[8];
int index_q = 7, i;
int D;
int quanzhong = 0;
int num = 0;
bool flag = true;
int main(){
    cin >> kaishi >> D;
    while(kaishi[0] != '-'){
        
        for(i = 0; i < 7; i++){
            if(kaishi[i] ==  0){
                index_q = i;
                break;
            }
        }
        
        quanzhong = 1;
        for(i = 0; i < index_q; i++){
            num += (kaishi[i] - '0')*quanzhong;
            quanzhong *= D;
        }
        
        int bianjie = (int)(sqrt(num)+0.5);
        for(i = 2; i< bianjie; i++){
            if(num % i == 0 || num %2 == 0){
                flag = false;
                break;
            }
        }
        
        if(flag) cout << "Yes" <<endl;
        else cout << "No" << endl;
        cin >> kaishi >> D;
    }
    return 0;
}

參考別人代碼如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,d;
    while(cin>>n){
        if(n<0)
            break;
        cin>>d;
        int flag=0;
        for(int i=2;i*i<=n;++i)
            if(n%i==0)
                flag=1;
        int a[27]={0};
        int cnt=0;
        while(n){
            a[++cnt]=n%d;
            n/=d;
        }
        int x=0;
        for(int i=1;i<=cnt;++i){
            x*=d;
            x+=a[i];
        }
        if(x==1)
            flag=1;
        for(int i=2;i*i<=x;++i)
            if(x%i==0)
                flag=1;
        if(flag)
            cout<<"No"<<"\n";
        else
            cout<<"Yes"<<"\n";
    }
    return 0;
}

收獲

  • 不用sqrt,用i*i < n

8、Phone Bills
題意:計算電話賬單
輸入:24個數(shù)

這是一道考察基本功和邏輯的題,沒有太多算法,讀懂題意就是算法。

題目有點難懂,其次,要使用map
map中的所有數(shù)據(jù)都是有序的
用法如下

std:map<int, string> personnel;
這樣就定義了一個用int作為索引,并擁有相關聯(lián)的指向string的指針.

難度略大,如果真實遇到了大概率放棄

前面有點都是這種數(shù)據(jù)處理題,倒著開始做

9、Heap Paths
之前測過
題意:遍歷每一條路徑
限制:節(jié)點N <= 1000
考察:堆、深度優(yōu)先遍歷

10、Vertex Coloring
做過

限制:N、M < 10^4
代碼實現(xiàn)如下:

#include <iostream>
#include <vector>
#include <set>
using namespace std;
struct node { int t1, t2; };
int main() {
    int n, m, k, i;
    cin >> n >> m;
    vector<node> v(m);
    for (i = 0; i < m; i++) cin >> v[i].t1 >> v[i].t2;
    cin >> k;
    while (k--) {
        int color[10009] = { 0 };
        bool flag = true;
        set<int> se;
        for (i = 0; i < n; i++) {
            cin >> color[i];
            se.insert(color[i]);
        }
        for (i = 0; i < m; i++) {
            if (color[v[i].t1] == color[v[i].t2]) {
                flag = false;
                break;
            }
        }
        if (flag)
            printf("%d-coloring\n", se.size());
        else
            printf("No\n");
    }
    return 0;
}

收獲:

  • <set>中的數(shù)據(jù)是已經(jīng)排好序的,并且不重復,可以用來計數(shù)

11、Decode Registration Card of PAT
限制:N card的數(shù)量 < 10^4,M查詢的數(shù)量 < 100
考察:對數(shù)據(jù)的處理
思路:用結構體來存儲每條信息,根據(jù)不同的type輸出

參考如下文章:
https://blog.csdn.net/liuchuo/article/details/84973049

收獲:

  • 如果<map> 超時,換成 unordered_map
  • 一些庫函數(shù),輸出時很方便
  • auto

12、Google Recruitment
題意:找某個固定數(shù)字的素數(shù)
考察:素數(shù)篩法吧?
是找素數(shù),但是沒用素數(shù)篩,直接常規(guī)的方法

收獲:

  • 截一個string字符串

13、LCA in a Binary Tree
給出樹的中序和前序遍歷,構建出這棵樹,再遞歸查找公共祖先

09.06

1、上題LCA
我恨自己明明有時間為什么不看他!說不定能多對一道題呢!
雖然沒寫出來,但是很接近了。

頭文件如下
#include<iostream>
#include<cstdio>
#include<map>  為了方便映射,用了map
using namespace std;

const int maxn = 10010;
int in[maxn];
int pre[maxn];

定義節(jié)點的數(shù)據(jù)結構,一個數(shù)值兩個指針
struct node{
    int val;
    node* left;
    node* right;
};


map<int,node*>mp; 定義一個map映射,int型為節(jié)點的數(shù)值,node*為左節(jié)點和右結點

創(chuàng)建,有四個參數(shù),分別是起始位置和終止位置
node* create(int preL,int preR,int inL,int inR){ 
 
    if(inL>inR) return NULL;  這個是循環(huán)結束的終止條件
    
    node* now = new node;  創(chuàng)建一個節(jié)點,作為這次找到的節(jié)點
    now->val = pre[preL];  這個值是 先序遍歷的第一個值
  
    int i;
    for(i=inL;i<=inR;i++){
        if(in[i]==pre[preL]) break;  在中序遍歷中找到根節(jié)點的位置
    }

    int numLeft=i-inL;    左子樹的節(jié)點的數(shù)目。
    now->left=create(preL+1,preL+numLeft,inL,i-1);  改變位置,這里的參數(shù)要理解。
    now->right=create(preL+numLeft+1,preR,i+1,inR);
    mp[now->val]=now;  把結點弄到mp中
    return now;
}

這個是根據(jù)題意來的,就是我們要
node* lca(node* root,node* a,node* b){
    if(root==NULL || root==a || root==b) return root;  特殊情況
    node* L = lca(root->left,a,b);向下查找
    node* R = lca(root->right,a,b);
    if(L==NULL) return R;
    if(R==NULL) return L;
    return root;
}

int main()
{
    int m,n;
    scanf("%d %d",&m,&n);
    for(int i=0;i<n;i++){
        scanf("%d",&in[i]);
    }
    for(int i=0;i<n;i++){
        scanf("%d",&pre[i]);
    }  輸入
    node* root = create(0,n-1,0,n-1);  建樹
   
   for(int i=0;i<m;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        if(!mp[a] && !mp[b]) printf("ERROR: %d and %d are not found.\n",a,b);
        else if(!mp[a]) printf("ERROR: %d is not found.\n",a);
        else if(!mp[b]) printf("ERROR: %d is not found.\n",b); 
        輸出錯誤提示

        else{
            node* res = lca(root,mp[a],mp[b]);  找到結果
            if(res->val==a)
                printf("%d is an ancestor of %d.\n",a,b);
            else if(res->val==b)
                printf("%d is an ancestor of %d.\n",b,a);  特殊輸出
            else
                printf("LCA of %d and %d is %d.\n",a,b,res->val);
        }
    }

    return 0;
}

留下了悔恨的淚水??

09.07

1、Travelling Salesman Problem
問題:求最短路徑,回到原始點
限制:頂點數(shù)N < 200, M < 100, 接下來輸出K條路徑




不懂Dijkstra算法為什么有個沒有用到的i的for循環(huán)

1、進制轉換
題目要求:十進制轉為二進制
限制:數(shù)字很大,個數(shù)可能為30個數(shù)字/ 數(shù)字是非負數(shù)。
難點:數(shù)字很長,不能用普通的整型來表示,需要分割、處理等。

正好是上道題說的 用vector來實現(xiàn)

代碼實現(xiàn)如下:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

string Divide(string str, int x){
    int reminder = 0;
    for(int i = 0; i < str.size(); i++){
        int current = reminder * 10 + str[i] - '0';
        str[i] = current / x + '0';
        reminder = current % x;
    }
    int pos = 0;
    while(str[pos] == '0')
        pos++;
    return str.substr(pos);
}

int main()
{   string str;
    while(cin >> str){
        vector <int> binary;  對于每次輸入,創(chuàng)建一個int 型的binary。
      
        while(str.size() != 0){
            int last = str[str.size() - 1] - '0';    取出來最后的數(shù)字
            binary.push_back(last % 2);   把最后一位處理,放入
            str = Divide(str, 2);
        }

        for(int i = binary.size() - 1; i >= 0; i--){
            cout << binary[i]; 輸出
        }
        cout << endl;
    }
    return 0;
}

才疏學淺,看不懂??戳硪粋€,通過C語言實現(xiàn)

#include <stdio.h>

int conversion(int x,int y,int s[],int d[],int n)
{
    int size=0;
    int i,j,k;
    i=0;
    while(i<n)
    {
        int carry=0;
        for(j=i;j<n;j++)
        {
            int t=(s[j]+carry*x)%y;
            s[j]=(s[j]+carry*x)/y;
            carry=t;
        }
        d[size++]=carry;
        while(s[i]==0&&i<n) i++;
    }
    return size;
}

int main()
{
    int dst[1000];
    int src[1000];
    char str[32];  
    while(scanf("%s",str)!=EOF)
    {
        int i;
        int len=strlen(str);
        for(i=0;i<len;i++)
        {
            src[i]=str[i]-'0';
        }
        int n=conversion(10,2,src,dst,len);
        for(i=n-1;i>=0;i--) printf("%d",dst[i]);
        printf("\n");
    }
}

輸入的長整型保存在str[]中。使用了一個函數(shù)進行轉換。把10進制轉為2進制。

https://www.nowcoder.com/practice/0337e32b1e5543a19fa380e36d9343d7?tpId=40&&tqId=21332&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

1、A+B for Polynomials
題目:A和B是多項式,求A+ B
限制:k<=10, N <= 1000

2、例題:給定前序和后序,計算中序有幾種情況。
這是一個定式,前序,后序給定,劃分子問題時,可能有多種左右子樹的劃分方式,參見柳神對 PAT 1119 的解答,適當變形即可.

知識點:先序中序后序
限制:節(jié)點數(shù)N <= 30

代碼實現(xiàn)

#include <iostream>
#include <vector>
using namespace std;
vector<int> in, pre, post;
bool unique = true;

void getIn(int preLeft, int preRight, int postLeft, int postRight) {
 
  只剩下一個節(jié)點了,直接入即可
   if(preLeft == preRight) {
        in.push_back(pre[preLeft]);
        return;
    }

根節(jié)點符合情況,
    if (pre[preLeft] == post[postRight]) {
        int i = preLeft + 1; //左子樹的開始
        while (i <= preRight && pre[i] != post[postRight-1]) i++; //找到右子樹的根節(jié)點,即左右子樹的分界線,用i表示。
        if (i - preLeft > 1)  //左子樹還能再劃分
            getIn(preLeft + 1, i - 1, postLeft, postLeft + (i - preLeft - 1) - 1);
        else  //左子樹只有一個,或者沒有左子樹,這個節(jié)點來回移動
            unique = false;   沒懂
        in.push_back(post[postRight]);
        getIn(i, preRight, postLeft + (i - preLeft - 1), postRight - 1);
    }

}
int main() {
    int n;
    scanf("%d", &n);
    pre.resize(n), post.resize(n);
    for (int i = 0; i < n; i++)
        scanf("%d", &pre[i]);
    for (int i = 0; i < n; i++)
        scanf("%d", &post[i]);
    getIn(0, n-1, 0, n-1);
    printf("%s\n%d", unique == true ? "Yes" : "No", in[0]); 
    for (int i = 1; i < in.size(); i++)
        printf(" %d", in[i]);
    printf("\n");
    return 0;
}

收獲:

  • 如果出現(xiàn) reference to 'xxxxxxx' is ambiguous,可能是定義的變量和庫中的某個變量撞名字了,把變量的名字改掉就可以了。
  • vector 里面的resize,可以設置內(nèi)存大小

3、PAT考綱
參考 http://m.itdecent.cn/p/3814d99bed25

PAT-A總共有4題,時間為3小時。三四大題 是一題圖、一題樹的概率較大,偶爾動態(tài)規(guī)劃,貪心算法等。 第二題 一般是STL(map,set,vector為主,偶爾隊列,堆棧)。第一題小題(邏輯題,字符串處理,數(shù)學,枚舉),要么簡單,要么讀題復雜理解復雜情況不容易想到,但是程序不會太復雜。其他的比如排序、查找、哈希、遞歸、遞推、尺取法、哈夫曼、鏈表、素數(shù)的判斷、數(shù)學問題、模擬、邏輯什么的,不需要復習,一般都融在題目里,是最基本的,看能力。

https://www.liuchuo.net/999-9

浙大2019原題:
happy 數(shù):任給一個數(shù),求其各位平方和,求迭代到 1 所需次數(shù),或者形成圈的起始數(shù)
給定無序數(shù)組排序給定寬度并用 Zig zag 輸出(PAT 原題)
給定前序判斷是否是 avl 樹(PAT 原題)
給定圖,給定頂點子集,排序輸出頂點子集圖中度前 3 的點,度相同輸出編號小的

https://pintia.cn/problem-sets/994805148990160896/problems/994805156145643520

字符串處理

一個很長(長度為 t)的數(shù)字字符串,要求刪除 kk \le t) 個數(shù),使得得到的數(shù)最小。(60/100)
需要思考的較多,寫起來很簡單。越大的數(shù),越先刪除,對于需要刪除的同等大小的數(shù),其余的數(shù)都不比他大,所以先刪除前面的。但是有特殊情況需要考慮,例如 219,刪除 1 位的最佳選擇應該是直接刪除 2 而不是 9,因為這樣會使最高位得以降低。這種情況需要優(yōu)先處理。我當時就沒有考慮到。

動態(tài)規(guī)劃

男孩女孩排列問題,要求連續(xù)男孩的個數(shù)不超過 k 個的可能的排列個數(shù)。(70/100)
動態(tài)規(guī)劃問題,劃分子問題求解。當時使用的遞歸結果超時了。

PAT頂級 1004 To Buy or Not to Buy - Hard Version (35分) 不會做

做題還有:九度教程

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容