1. 程式人生 > >Noip初賽整理

Noip初賽整理

turn 次數 tps 錯題 包含 strong 環境 對稱性 而且

分辨率為 1600x900、 16 位色的位圖,存儲圖像信息所需的空間為?
A. 2812.5KB B. 4218.75KB C. 4320KB D. 2880KB
A
1 kb = 1024 byte
16/2 = 8 byte
正數的反碼是其本身
負數是除了符號位之外依次取反
正數的補碼是本身
負數的補碼 是 反碼加1
只要考到了一般都是負數,因為正數就是一個進制轉換沒啥好考的。。。

存儲器,運算器,控制器,輸入輸出設備

主機由cpu和內存ram組成
rom只讀不可寫入,貌似存了些底層操作
外設由外存(硬盤),輸入輸出設備組成
以上構成了硬件系統

總線結構 DB AB CB數據地址控制總線
地址單向,寬度決定存儲器容量大小 數據雙向

32bit地址總線能用2^32字節, 即4 * 2 ^ 30 = 4GB

一棵滿二叉樹若有k層,那麽節點共有2 ^ k - 1 個 ,並且其第k層節點數為2 ^(k-1)

二進制和16進制互化:
0101 1101 1111.1001
5 D F . 9

觸摸屏輸入輸出設備都算是。。。

什麽不是個人電腦的硬件組成部分? 虛擬內存(不算硬件
錯排公式
\[D_n=n! \sum_{i=0}^n(-1)^i \frac{1}{i!}\]
二項式定理:

\[(a+b)^n= \sum_{k=0}^nC_n^ka^{n-k}b^k\]

常用的電子郵件協議有SMTP、POP3、IMAP4,它們都隸屬於TCP/IP協議簇

WWW

選擇題有:下列正確的程序段為?這種題註意“=”的含義是賦值,因為說了是程序段

初賽的代碼填空可能有點水,但是選擇和問題求解並不水,真的可能需要用到復雜的方法(比如DP。。。)

註意倒序存儲
加法
洛谷P1601
兩種寫法,我更偏向於add函數裏的寫法

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 10000 + 10;
string a1,b1;
int a[MAXN], b[MAXN], c[MAXN];
void add(int a[], int b[], int c[], int la, int lb) {
    int len = max(la, lb), x = 0;
    for(int i=1; i<=len; i++) {
        c[i] = a[i] + b[i] + x;
        x = c[i] / 10;
        c[i] %= 10;
    }
    if(x != 0) c[++len] = x;
    for(int i=len; i; i--) {
        cout << c[i];
    }
}
int main() {
    cin >> a1 >> b1;
    if(a1[0] == '0' && b1[0] == '0') {//這種寫法先判0,並且註意是字符0不是整數0,不能用!
        cout << "0";
        return 0;
    }
    int la = a1.length(), lb= b1.length();
    /*
    for(int i=0; i<la; i++) {
        a[la - i] = a1[i] - '0';
    }
    for(int i=0; i<lb; i++) {
        b[lb - i] = b1[i] - '0';
    }
    add(a, b, c, la, lb)
    */
    for(int i=0; i<la; i++) {
        a[la-i-1] = a1[i] - '0';
    }
    for(int i=0; i<lb; i++) {
        b[lb-i-1] = b1[i] - '0';
    }
    int tot = max(la, lb), x = 0;
    for(int i=0; i<tot; i++) {
        c[i] += a[i] + b[i];//這裏是+=,進位都算好了
        if(c[i] >= 10) {
            c[i+1]++;
            c[i] -= 10;
        }
    }
    tot++;
    while(!c[tot]) tot--;
    for(int i=tot; i>=0; i--) {//這裏是從tot開始,因為為0部位已經刪去
        cout << c[i];
    }
    return 0;
} 

減法
洛谷P2142
乘法
洛谷P1303
高精除低精
洛谷P1480

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 10000 + 10;
string a1,b1;
int a[MAXN], b[MAXN], c[MAXN], d;
void add(int a[], int b[], int c[], int la, int lb) {
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    int len = max(la, lb), x = 0;
    for(int i=1; i<=len; i++) {
        c[i] = a[i] + b[i] + x;
        x = c[i] / 10;
        c[i] %= 10;
    }
    if(x != 0) c[++len] = x;
    for(int i=len; i; i--) {
        cout << c[i];
    }
}
void subt(string a1, string b1) {
    string c1;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    bool flg = false;
    if(a1.length() < b1.length() || (a1.length() == b1.length() && a1 < b1)) {
        c1 = a1;
        a1 = b1;
        b1 = c1;
        flg = true;
    }
    if(flg) cout << "-";
    int la = a1.length(), lb = b1.length();
    for(int i=0; i<la; i++) {
        a[la-i] = a1[i] - '0';
    }
    for(int i=0; i<lb; i++) {
        b[lb-i] = b1[i] - '0';
    }
    int x = 0;
    for(int i=1; i<=la; i++) {
        c[i] = a[i] - b[i] - x;
        x = (c[i] < 0) ? 1 : 0;
        c[i] = (c[i] < 0) ? c[i] + 10 : c[i];
    }
    while(!c[la] && la > 1) la--;
    for(int i=la; i; i--) {
        cout << c[i];
    }
}

void multi(string p, string q) {
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    int lp = p.length(), lq = q.length();
    for(int i=0; i<lp; i++) {
        a[lp-i] = p[i] - '0';
    }
    for(int i=0; i<lq; i++) {
        b[lq-i] = q[i] - '0';
    }
    int len = lp + lq - 1;
    for(int i=1; i<=lp; i++) {
        for(int j=1; j<=lq; j++) {
            c[i+j-1] += a[i] * b[j];
            c[i+j] += c[i+j-1] / 10;
            c[i+j-1] %= 10;
        }
    }
    if(c[len+1] >= 1) len++;
    while(!c[len] && len > 1) len--;
    for(int i=len; i; i--) {
        cout << c[i];
    }
}

void divi(string p, int q) {
    int lp = p.length(), x = 0, s = 0, tot = 0;
    for(int i=0; i<lp; i++) {
        x = x * 10 + p[i] - '0';
        if(x / q != 0) s++;
        if(s == 0) continue;
        c[++tot] = x/ q;
        x %= q;//x就是最後的余數
    }
    for(int i=1; i<=tot; i++) {
        cout << c[i];
    }
}
int main() {
    cin >> a1 >> d;
    divi(a1, d); 
    return 0;
}

完形填空

做完題之後一定要整理思路檢查一次!,因為一個陌生的題當我們模擬完之後就比較熟悉,這個時候重走一遍不僅輕車熟路,更可以找到第一次模擬疏忽的地方,避免錯誤

註意對稱寫代碼,以及造個小數據帶進去試試

填程序空的時候註意不要被給的代碼帶歪了。。。因為給的代碼都很奇怪,到最後自己可能被帶的也填了奇怪的東西。。。要按“目前需要做什麽”來填,比如填取最優什麽的,根據你自己對算法的理解,結合上下文填空。我最後一個空就因為給的代碼太簡單導致我以為簡單到不用更新最優解。。。其實按這個算法的流程來說就應該是取最優,不能被帶歪了。。。

註意邊界問題,代進去看一看是否能取到邊界,很多時候初始化的值和題目描述是有點不符的,特別是最後一個空,一般是某個指針-1,這個-1就是坑人的。。。而且經常有把全局變量初始化為0的情況,得仔細看看符不符合,若是一個空填上之後會越過邊界,比如什麽i + p 發現會超過n什麽的,可能是填錯了,做這種題的技巧就是盡量去填給你的代碼中本來就有的,有一些是形式上具有對稱性,還有一些是比較特殊的,定義了一個end2 = n,end2始終沒改變過,所以填n填end2都一樣,但是答案還是寫了end2。。。(13年填空1)
註意填空的對稱性,比如要判斷兩個變量哪個先寫到if裏面,變量名的順序都是能從前的代碼裏能看出的

初賽代碼經常有for不打花括號什麽的奇怪操作,有時候會影響到理解(比如說一句要填的空在不在循環裏面什麽的)

如果說填代碼的時候,顯然會算的超過題目邊界,即使這樣沒多大影響,估計也是填錯了,比如15年最後一個填空題最後一個空,顯然0 和 2 是需要遍歷的,據此可得i-1和i+1,並不是說無所謂就不用遍歷。。。

如果看到一個很奇怪的地方, 不要輕易地認為是出題人故意寫出來坑人什麽的,除非真的能確定,“聰明反被聰明誤”
例如10年完型T1那個swap,因為傳了個指針我就以為這是個無效的操作,但其實我根據swap這個名就該明白這是出題人幹擾我的,如果不交換這個程序輸出什麽啊。。。


閱讀理解

好好讀題好好讀題好好讀題,從題幹中挖掘一些信息!做題的時候一定要專註冷靜認真,別再犯低級錯誤了!

註意閱讀程序的時候很有可能坑人,比如數組下標從0開始存

先找規律,找到解決小範圍問題的辦法,然後多造幾個數據觀察一下有什麽關系,最好先讀一遍代碼看看是做什麽的,再去模擬
解決那種很難思考的遞歸程序要麽猜那個程序是幹什麽的,要麽暴力算

但是暴力算也有技巧,比如不要用深度優先的方式去展開搜索樹,很容易亂,用廣搜的方式展開搜索樹有條不紊,還容易看出規律。並且記著加一些記憶化,算的次數越少越不容易錯!(17年閱讀T1)

總的來說就是深度優先發現規律,廣度優先計算結果

例如10年閱讀T4,本質是博弈,但是其實挺難看出來的,如果用廣度優先的方式展開估計是算不完的,但是如果以深度優先的方式,找最特殊的,很容易就會發現r(6) = -1,r(7) = 1,然後就會發現規律
但是因為題型不定,有時深搜反而不好找規律,靈活變換才是通法

明確數組代表的含義後再做一遍

有的題註意把過程圖像化,比如17年閱讀程序最後一題

寫遞歸的時候註意寫下各種狀態參量,比如i = 1,q = 3什麽的,不要怕麻煩,也別急著返回,把第0層遞歸寫出來
比如f(0,1,6) f(0,2,6)這樣的,一目了然,不容易錯

千萬不要“松懈”,有疑惑的地方一定要抓住然後重新推導解決疑惑(比如一個運算滿不滿足交換律舉個例子試試),好多次我犯了明顯的錯誤還是因為懶得推放過了不大明確的地方,還有是求到最後一步不想幹了,直接胡想答案上去(潛意識中),也沒考慮其正確性,從第一步到最後一步都要認真的做,然後回頭再檢查一遍,看得清楚一點!

考試前要有意識地讓自己進入狀態


關於心態

不要一個題做不出來就郁悶,也不要一個題輕易看出解法就十分得意,這個時候往往容易掉進坑裏,比如13年填空最後一題第三個和第四個,我根據我所謂的對稱性,想都沒想,類比上面的代碼反著寫了一波,然後發現不用反著寫,因為他這兩部分形式上是一樣的。。。檢查的時候還沒發現這個問題(當時心態飄了),至少也得仔細看看思考一下吧。。。


錯題

做題的時候一定要細心,有些答案一看就不對得好好想想。。。

二進制轉十進制的時候要從0開始數

不要因為初賽的題意簡單就不怎麽細想直接做,事實上也要當一道題去認真思考模型,以及應該怎麽去完成這件事情,用自己所學的知識認真對待!

用1,1,2,4,8,8 這幾個數,組合成四位數,能有多少種組合?
難算但是數據小可以直接枚舉組合
我組合是列舉出來了,但是思維定勢,導致我直接用A(4, 4)去計算答案
實際上每一步都要思考一下不要憑感覺就直接乘A(4,4),既然分類了,說不定計算也是分類的,乘之前要看看是不是都能乘
因為像 1 1 2 8 這樣的組合全排列,會有重復,需要除以2,所以像1 1 2 8 排列一下只有12種不同的四位數
相比之下 1 2 4 8 有24種

10閱讀T4
perm函數求的是字典序最小的!!!我還想了半天多個解是不是只有一個滿足條件的,我以為swap換不出全排列。。。事實上感性理解函數是幹什麽的就好,比如這題的perm函數應該是求全排列的,證明不出來就先放著吧

(13年選擇15)T(n)表示某個算法輸入規模為 n 時的運算次數。如果 T(1)為常數,且有遞歸式 T(n) = 2*T(n / 2) + 2n,那麽 T(n) = ( )
A. Θ(n)
B. Θ(n log n)
C. Θ(n2)
D. Θ(n2 log n)
B
感性理解下

(13年選擇7)
斐波那契數列的定義如下:F1 = 1, F2 = 1, Fn = Fn – 1 + Fn – 2 (n ≥ 3)。如果用下面的函數計 算斐波那契數列的第 n 項,則其時間復雜度為( )。

int F(int n) 
{ 
 if (n <= 2) 
  return 1; 
 else 
  return F(n - 1) + F(n - 2); 
}

A. O(1)
B. O(n)
C. O(n2)
D. O(Fn)

其實一看就該選D,如果選ABC你想想這個題還用考嗎。。。

一個求方案或者什麽的題不會做就想想卡特蘭數什麽的,套一下試試

(12年選擇16)
已知帶權有向圖 G 上的所有權值均為正整數,記頂點 u 到頂點 v 的最短路徑的權值為 d(u, v)。若 v1, v2, v3, v4, v5 是圖 G 上的頂點,且它們之間兩兩都存在路徑可達,則以下說法正確的有( )。

A. v1到v2的最短路徑可能包含一個環
B. d(v1,v2)=d(v2,v1)
C. d(v1,v3)≤d(v1,v2)+d(v2,v3)
D. 如果v1→v2→v3→v4→v5是v1到v5的一條最短路徑,那麽v2→v3→v4是v2到v4的一條最短路徑
CD 註意是有向圖

(09選擇4)
在字長為16位的系統環境下,一個16位帶符號整數的二進制補碼為1111111111101101。其對應的十進制整數應該是:
A. 19
B. -19
C. 18
D. -18
B
二進制減1,若最後一位為1,則讓最後一位減1變為0,若為0,就向前面借一位
(我看到好多個16居然把這個數按16進制展開成10進制了)

5 %10 = 5

Noip初賽整理