日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

2019CSP-J第一輪測(cè)試詳細(xì)講解

 長(zhǎng)沙7喜 2019-10-20

今天,胖頭魚老師要為大家?guī)硪环軨SP-J組的詳細(xì)解題報(bào)告。

其中展現(xiàn)的是胖頭魚老師親臨考場(chǎng)時(shí)的(緊張)思維。

一、單項(xiàng)選擇題

  1. 考察域名常識(shí)。

    中國(guó)的頂級(jí)域名是.cn,china的縮寫。

  2. 考察二進(jìn)制位運(yùn)算。

    將兩個(gè)二進(jìn)制表示的數(shù)對(duì)齊以后逐位作邏輯運(yùn)算,與運(yùn)算是兩個(gè)數(shù)都為1時(shí)結(jié)果為1,否則為0,最后得到答案01 0010 1000 0011。

  3. 考察二進(jìn)制位的計(jì)數(shù)單位。

    一個(gè)字節(jié)占8位,所以32位整數(shù)占4個(gè)字節(jié)。

  4. 考察程序的三大結(jié)構(gòu),循環(huán)結(jié)構(gòu)中的for語句。

    循環(huán)從1到c一共是c次,每一次s都會(huì)-1,所以一共是-c,結(jié)果為a - c。

  5. 考察二分算法。

    折半查找每次可以將查找范圍減半,2^7 = 128 > 100,所以需要7次查找。

    也可以根據(jù)查找范圍一個(gè)個(gè)數(shù),50、25、12、6、3、1、0,7次查找后查找范圍為0。

  6. 考察數(shù)據(jù)結(jié)構(gòu)鏈表的特性。

    鏈表只記錄前一個(gè)元素和后一個(gè)元素,所以可以根據(jù)需要來分配空間,插入、刪除的時(shí)候也不存在移動(dòng)這個(gè)說法。

    但是不能像數(shù)組一樣支持隨機(jī)訪問。

  7. 考察組合數(shù)學(xué),或者枚舉算法。

    球和袋子都是相同的,所以只考慮裝入袋子的球的數(shù)量,并且裝的時(shí)候每個(gè)袋子中球的數(shù)量是不減的。

    組合數(shù)學(xué)苦手的同學(xué)可以扳指頭數(shù),只用數(shù)4個(gè)袋子就行了,一共18種。

    袋子   1         2        3        4        方案數(shù)

                0        0        0       0~4    5

                0        0        1        1~3    3

                0        0        2       2~3    2

                0        1         1        1~3    3

                0        1         2        2         1

                0        2        2         2        1

                1        1         1         1~2    2

                1        1         2         2        1

  8. 考察數(shù)據(jù)結(jié)構(gòu)二叉樹的存儲(chǔ)。

    題目中其實(shí)已經(jīng)提示了編號(hào)的方式,所以沒學(xué)過二叉樹也沒關(guān)系。

    根據(jù)圖可以計(jì)算出每個(gè)節(jié)點(diǎn)的編號(hào),其中右下角的等于15,是最大的 。

  9. 考察數(shù)學(xué),素?cái)?shù)判斷。

    不熟悉100以內(nèi)素?cái)?shù)的同學(xué)可以逐個(gè)試除一下,得到97。

  10. 考察數(shù)學(xué),約數(shù)判斷和求公約數(shù)。

    377 - 319 = 58,答案就很明顯了是29的倍數(shù)。

  11. 考察貪心算法,或者枚舉算法。

    可以優(yōu)先嘗試跑性價(jià)比高的一小時(shí)方案,發(fā)現(xiàn)正好跑3次一小時(shí)再加2次半小時(shí)可以達(dá)到21公里,然后算出消耗了2400卡。

  12. 考察數(shù)學(xué),抽屜原理。

    一共有4種花色的牌,抽13張,每種花色都有3張時(shí)還多出1張,所以至少有4張牌花色相同。

  13. 考察組合數(shù)學(xué)。

    五位數(shù)的中間位顛倒以后還是中間位,所以只能填寫0、1、8,第1位和第2位顛倒以后確定了第4位和第5位,分別可以填寫0、1、8、6、9。

    所以一共是3 * 5 * 5 = 75種。

  14. 考察數(shù)據(jù)結(jié)構(gòu),二叉樹的遍歷。

    根據(jù)中序遍歷和后序遍歷的特性,可以畫出圖,得到前序遍歷為ABDEGHJCFI。

  15. 考察計(jì)算機(jī)常識(shí)。

    圖靈是計(jì)算機(jī)領(lǐng)域的人物。

二、閱讀程序

  1. 程序大意:對(duì)于字符串中的第i位,如果i是n的約數(shù),并且第i個(gè)字符比'a'(97)要大,就減少'a'(97)-'A'(65)。

    #include <cstdio>#include <cstring>using namespace std;char st[100];int main() {  scanf('%s', st); int n = strlen(st); // 計(jì)算字符串的長(zhǎng)度 for (int i = 1; i <= n; ++i) { // 對(duì)字符串中的第i個(gè)字符進(jìn)行循環(huán)枚舉 if (n % i == 0) { // 判斷i是否是n的約數(shù) char c = st[i - 1]; // 取出字符串中的第i個(gè)字符 if (c >= 'a') // 判斷字符是否大于97 st[i - 1] = c - 'a' + 'A'; // 將字符減少32 } } printf('%s', st); // 輸出字符串 return 0;}

    1)考察程序的輸入輸出。

          程序中沒有對(duì)字符串中的字符范圍進(jìn)行任何要求。

    2)考察表達(dá)式運(yùn)算,除法和取模。

           如果i = 0,那么在n對(duì)i進(jìn)行取模運(yùn)算時(shí)就會(huì)報(bào)錯(cuò),因?yàn)槌?了。

    3)考察約數(shù)判斷,注意不是素?cái)?shù)判定。

           判斷素?cái)?shù)的時(shí)候通常用這種方式進(jìn)行加速,是因?yàn)閟qrt(n)之后的約數(shù)與之前的約數(shù)是一一對(duì)應(yīng)的,這也就說明了sqrt(n)之后還有約數(shù)。

           如果將循環(huán)范圍縮小了,就不會(huì)處理后面的約數(shù),導(dǎo)致答案不一樣。

    4)考察數(shù)據(jù)類型,字符型的存儲(chǔ)與表示。

           大寫字母的ASCII碼都要小于'a'(97),所以不會(huì)對(duì)字符串進(jìn)行修改。

    5)考察數(shù)學(xué),約數(shù)數(shù)量計(jì)算。

           將要計(jì)算的數(shù)分解質(zhì)因數(shù),每個(gè)質(zhì)因數(shù)的出現(xiàn)次數(shù)加1,再乘起來就是約數(shù)個(gè)數(shù)。

           最多時(shí)每個(gè)約數(shù)的位置都可以修改,18有6個(gè)約數(shù)。

    6)考察數(shù)學(xué),約數(shù)數(shù)量計(jì)算。

           10000 = 2^5 * 5^5,一共有(5 + 1) * (5 + 1) = 36個(gè)約數(shù)。

           不會(huì)求約數(shù)個(gè)數(shù)的同學(xué)可以暴力算一下其他幾個(gè)數(shù)的約數(shù)個(gè)數(shù),用排除法也能得到這個(gè)答案。

  2. 程序大意:有ab兩組元素,兩組元素之間可以兩兩配對(duì)(0可以任意次配對(duì))。

    初始時(shí)所有元素都和另一組的0配對(duì),每次考察a組的第x個(gè)元素和b組的第y個(gè)元素,如果這兩個(gè)元素之前的配對(duì)交叉了,則把它們之前的配對(duì)元素都重新配對(duì)到0,并將這兩個(gè)元素配對(duì)。

    最后求有多少個(gè)元素和0配對(duì)。

    #include <cstdio>using namespace std;int n, m;int a[100], b[100];
    int main() {  scanf('%d%d', &n, &m); // n個(gè)數(shù)與m次操作 for (int i = 1; i <= n; ++i) // 初始時(shí)所有數(shù)都跟0配對(duì) a[i] = b[i] = 0;  for (int i = 1; i <= m; ++i) { int x, y;    scanf('%d%d', &x, &y);    if (a[x] < y && b[y] < x) { // 對(duì)于想要配對(duì)的數(shù),判斷原先的一對(duì)配對(duì)是否交叉      if (a[x] > 0) // 將原先的配對(duì)元素重新和0配對(duì) b[a[x]] = 0; if (b[y] > 0)        a[b[y]] = 0;      a[x] = y; // 當(dāng)前兩個(gè)元素建立新的配對(duì) a[y] = x; } } int ans = 0;  for (int i = 1; i <= n; ++i) { // 統(tǒng)計(jì)和0配對(duì)的元素?cái)?shù)量 if (a[i] == 0) ++ans; if (b[i] == 0) ++ans; } printf('%d\n', ans); return 0;}

    1)考察對(duì)程序含義的理解。

          m > 0時(shí)一定會(huì)有一個(gè)配對(duì),所以和0配對(duì)的元素的數(shù)量一定小于2n。

    2)考察對(duì)程序含義的理解,反例設(shè)計(jì)。

          統(tǒng)計(jì)是按照元素編號(hào)的順序進(jìn)行的,如果有一個(gè)x < y的配對(duì),那么統(tǒng)計(jì)完b中的第x個(gè)元素時(shí)ans會(huì)變成奇數(shù)。

    3)考察對(duì)程序含義的理解,反例設(shè)計(jì)。

           如果ab中的第i個(gè)元素進(jìn)行配對(duì),則a[i]和b[i]同時(shí)>0。

    4)考察對(duì)程序含義的理解,反例設(shè)計(jì)。

           x總是小于y不代表x之前沒有別的配對(duì),如果x之前有別的配對(duì),則照樣會(huì)執(zhí)行清理。

             可以依次對(duì)(1, 1)和(1, 2)進(jìn)行配對(duì),則第二次操作時(shí)會(huì)對(duì)1的配對(duì)進(jìn)行清理。

    5)考察對(duì)程序含義的理解。

          x和y兩兩不同時(shí),每次都會(huì)成功進(jìn)行配對(duì),m次會(huì)產(chǎn)生m對(duì)配對(duì),所以和0配對(duì)的元素?cái)?shù)量為2n - 2m。

    6)考察對(duì)程序含義的理解。

           x各不相同,y每次相等,那么x和y配對(duì)時(shí)每次都會(huì)清理掉之前的配對(duì),最終只會(huì)產(chǎn)生一組配對(duì),所以和0配對(duì)的元素?cái)?shù)量為2n - 2。

  3. 程序大意:將一個(gè)元素序列根據(jù)a值構(gòu)造成一棵二叉樹,每次在序列中選擇a值最小且最靠前的元素作為根,根之前的序列構(gòu)建左子樹,根之后的序列構(gòu)建右子樹。

    最后求出每個(gè)節(jié)點(diǎn)的深度乘以b值的和。

    #include <iostream>using namespace std;const int maxn = 10000;int n;int a[maxn];int b[maxn];int f(int l, int r, int depth) { // 計(jì)算序列中l(wèi)到r這幾個(gè)元素構(gòu)成的根深度為depth的子樹的權(quán)值 if (l > r) // 判斷空子樹 return 0; int min = maxn, mink; for (int i = l; i <= r; ++i) { // 查找a值最小的最靠左的元素 if (min > a[i]) { min = a[i]; // 記錄最小值 mink = i; // 記錄位置 } } int lres = f(l, mink - 1, depth + 1); // 計(jì)算左子樹 int rres = f(mink + 1, r, depth + 1); // 計(jì)算右子樹 return lres + rres + depth * b[mink]; // 當(dāng)前子樹的權(quán)值為左右子樹權(quán)值與根權(quán)值的和}int main() { cin >> n; for (int i = 0; i < n; ++i) // 讀入每個(gè)元素的a值 cin >> a[i]; for (int i = 0; i < n; ++i) // 讀入每個(gè)元素的b值 cin >> b[i]; cout << f(0, n - 1, 1) << endl; // 構(gòu)建子樹并計(jì)算權(quán)值 return 0;}

    1)考察循環(huán)遍歷數(shù)組,也可以直接進(jìn)行反例設(shè)計(jì)。

          重復(fù)的a值不影響查找最小元素,所以不會(huì)出錯(cuò)。

    2)考察對(duì)程序含義的理解。

           所有元素的b值為0,則權(quán)重也全部為0,總權(quán)重就是0。

           可以根據(jù)程序觀察一下,所有的計(jì)算都會(huì)和b值進(jìn)行相乘,沒有常數(shù),也可以猜到結(jié)果為0。

    3)考察數(shù)據(jù)結(jié)構(gòu)二叉樹,節(jié)點(diǎn)分層時(shí)的特性,最劣極端情況。

          每個(gè)子樹中的每個(gè)節(jié)點(diǎn)都會(huì)進(jìn)行一次比較,最壞情況下二叉樹有n層(每次只劃分出一個(gè)子樹),所以比較次數(shù)為100 + 99 + ... + 1 = 5050,與5000最接近。

    4)考察數(shù)據(jù)結(jié)構(gòu)二叉樹,節(jié)點(diǎn)分層時(shí)的特性,最優(yōu)極端情況。

          最少情況下二叉樹有l(wèi)og層,100個(gè)節(jié)點(diǎn)約為7層,每一層的總節(jié)點(diǎn)數(shù)估算為n,則比較次數(shù)大約為700次,與600最接近。

    5)綜合考察對(duì)程序含義的理解、二叉樹的結(jié)構(gòu)與數(shù)學(xué)計(jì)算。

          為了讓輸出最大,則需要讓b值大的元素深度盡可能的大,一條鏈可以達(dá)成這個(gè)要求,則權(quán)值為1^2 + 2^2 + ... + 10^2 = 385。

    6)綜合考察對(duì)程序含義的理解、二叉樹的結(jié)構(gòu)與數(shù)學(xué)計(jì)算。

           每個(gè)元素的b值均為1,則計(jì)算的是元素的深度和,所以需要讓二叉樹的深度盡可能小。

           那么第一層可以有1個(gè)節(jié)點(diǎn),第二層可以有2個(gè),第三層可以有4個(gè),以此類推。權(quán)值為1 * 1 + 2 * 2 + 4 * 3 + 8 * 4 + ... + 32 * 6 + 37 * 7 = 580,注意最后一層節(jié)點(diǎn)數(shù)不滿。

三、完善程序

  1. 程序思路:考察分治算法,通過遞歸的方式來對(duì)矩陣進(jìn)行填充。

    從0作為元開始,每次將當(dāng)前的矩陣劃分成四個(gè)子矩陣,對(duì)應(yīng)了一次變換,并根據(jù)變化規(guī)則分別得到四個(gè)子矩陣的元。

    子矩陣用遞歸的方式進(jìn)行填充,直到不再變換。

    #include <cstdio>using namespace std;int n;const int max_size = 1 << 10;
    int res[max_size][max_size]; // 01矩陣
    void recursive(int x, int y, int n, int t) { // 填充左上角為(x, y)的n階子矩陣,且元為t if (n == 0) { // 0階矩陣只有一個(gè)數(shù) res[x][y] = t; // 等于元,不再變換 return; } int step = 1 << (n - 1); // 分成的子矩陣之間的距離 recursive(x, y, n - 1, t); // 左上角的子矩陣,元不變 recursive(x, y + step, n - 1, t); // 右上角的子矩陣,元不變 recursive(x + step, y, n - 1, t); // 左下角哦的子矩陣,元不變 recursive(x + step, y + step, n - 1, !t); // 右下角的子矩陣,元取反}
    int main() { scanf('%d', &n); recursive(0, 0, n, 0); // 初始時(shí)要填充左上角為(0, 0)的n階子矩陣,初始時(shí)元為0 int size = 1 << n; // n階矩陣的寬度為2^n for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) printf('%d', res[i][j]); puts(''); } return 0;}

    下面講解一下對(duì)于不能完全看懂程序的同學(xué)該如何選擇。

    1)如果填寫一個(gè)常數(shù),那整個(gè)矩陣就是常數(shù)矩陣了。

          而且這個(gè)t在函數(shù)中傳遞下來就只有這里可以直接使用,其他地方都是參數(shù)。

           所以除了t也沒別的選擇。

    2)分成四個(gè)子矩陣,看不懂程序的根據(jù)另外兩行都能猜出來。

          另外兩行中可以發(fā)現(xiàn),x和y分別有加與不加兩種可能,組合起來正好四種可能,所以肯定沒減號(hào)。

    3)同上。

    4)通過函數(shù)中的參數(shù)命名可以猜出肯定是n了。

           然后測(cè)一下n = 1就可以確定第二個(gè)參數(shù)填0。

    5)測(cè)一下n = 1就知道肯定是1 << n。

  2. 程序思路:就是計(jì)數(shù)排序,和桶排序的原理有些相似。

    核心思想是,先統(tǒng)計(jì)每個(gè)值x出現(xiàn)的次數(shù),再計(jì)算出小于等于每個(gè)值x的元素?cái)?shù)量t,這個(gè)數(shù)量t決定了排序時(shí)值為x的元素應(yīng)該從第t大開始逐個(gè)往前排,這樣就完成了單關(guān)鍵字排序。

    雙關(guān)鍵字排序時(shí),要先排第二關(guān)鍵字,讓元素都是根據(jù)第二關(guān)鍵字有序的。然后根據(jù)第一關(guān)鍵字重新排序時(shí),首先可以保證結(jié)果是第一關(guān)鍵字有序的,同時(shí)對(duì)于第一關(guān)鍵字相同的元素,它們已經(jīng)按照第二關(guān)鍵字排好序了,所以最后的結(jié)果是雙關(guān)鍵字排序。

    #include <cstdio>#include <cstring>using namespace std;const int maxn = 10000000;const int maxs = 10000;
    int n;unsigned a[maxn], b[maxn], res[maxn], ord[maxn];unsigned cnt[maxs + 1];
    int main() { scanf('%d', &n); for (int i = 0; i < n; ++i) scanf('%d%d', &a[i], &b[i]); memset(cnt, 0 , sizeof(cnt)); // 清0統(tǒng)計(jì)數(shù)組 for (int i = 0; i < n; ++i) ++cnt[b[i]]; // 先對(duì)第二關(guān)鍵字排序,統(tǒng)計(jì)每個(gè)b值的數(shù)量 for (int i = 0; i < maxs; ++i) cnt[i + 1] += cnt[i]; // 累計(jì)小于等于每個(gè)b值的元素?cái)?shù)量 for (int i = 0; i < n; ++i) ord[--cnt[b[i]]] = i; // 根據(jù)第i個(gè)元素的b值,按照計(jì)算出的數(shù)量開始右后往前排列 memset(cnt, 0 , sizeof(cnt)); for (int i = 0; i < maxs; ++i) ++cnt[a[i]]; // 接下來對(duì)第一關(guān)鍵字排序,統(tǒng)計(jì)每個(gè)a值的數(shù)量 for (int i = 0; i < maxs; ++i) cnt[i + 1] += cnt[i]; // 累計(jì)小于等于每個(gè)a值的元素?cái)?shù)量 for (int i = n - 1; i >= 0; --i) // 因?yàn)榕判蛑兄迪嗤脑厥菑暮笸胺诺模藭r(shí)元素已經(jīng)按b值排好序了,所以要從后往前來放元素才能保證a值相同的元素b值是由小到大的 res[--cnt[a[ord[i]]]] = ord[i]; // 之前排好序的元素編號(hào)在ord中,要按照第二關(guān)鍵字排序來放 for (int i = 0; i < n; ++i) printf('%d %d\n', a[res[i]], b[res[i]]); // 雙關(guān)鍵字排序的結(jié)果在res中 return 0;}

    下面講解一下對(duì)于不能完全看懂程序的同學(xué)該如何選擇。

    1)先排第二關(guān)鍵字,肯定要選只有b[i]的選項(xiàng)。

    2)按照第二關(guān)鍵字排序,答案肯定跟b[i]相關(guān)。

           每個(gè)元素有ab兩個(gè)值,ord中只能記錄元素編號(hào),所以肯定是保存i。

    3)現(xiàn)在根據(jù)第一關(guān)鍵字排序,答案應(yīng)該是跟a[i]有關(guān)。

           有個(gè)與a[i]和b[i]同時(shí)有關(guān)的選項(xiàng)明顯越界了,肯定不可能。

    4) ord里面存的是元素編號(hào),肯定不能跟a[i]配合使用,而是要跟a[ord[i]]配合使用。

         同時(shí)這是根據(jù)第一關(guān)鍵字排序,應(yīng)該是與a有關(guān)。

    5)res和ord里面存的都是元素編號(hào),肯定不能嵌套使用。

           答案要按照排序輸出,肯定與res或者ord有關(guān)。

總體來說,題目還是出的挺好的,考察的知識(shí)點(diǎn)也比較全面,注重考察原理。

對(duì)于無法將知識(shí)點(diǎn)理解透徹的同學(xué),也要學(xué)會(huì)根據(jù)上下文的線索來推導(dǎo)的能力,可以在選擇題的考試中爭(zhēng)取更多的分?jǐn)?shù)。

逐月

https://www.

(請(qǐng)?jiān)谟?jì)算機(jī)上打開)

一個(gè)由中老年信息學(xué)愛好者傾情打造的網(wǎng)站

免費(fèi)提供各種信息學(xué)的學(xué)習(xí)資料

歡迎大家前來學(xué)習(xí)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章