CSP2020-J1-真題解析-完善程序


三、完善程序

1、質因數分解

#include <cstdio>
using namespace std;
int n, i;

int main() {
  scanf("d", &n);
  for(i = ①; ② <=n; i ++){
    ③{
      printf("%d ", i);
      n = n / i;
    }
  }
  if(④)
    printf("%d ", ⑤);
  return 0;

【分析】此題相對簡單,程序的思路,題目里的提示也說明的非常清楚,先從小到大枚舉變量 i,然后用 i 不停試除 n來尋找所有的質因子。
1、2
由於是求質因數,所以i必然是從最小的質數2開始。
2、

\[i*i \]

遍歷質因數的時候,范圍是2~

\[\sqrt{n} \]

所以循環判斷條件是i*i<=n
3、while(n%i==0)
對每一個i,判斷是否能整除當前n,若能整除則一直除,直到除不盡為止,然后繼續試下一個i
4、n>1
5、n
for循環遍歷完之后,還需要檢測下當前的n是否大於1,若是,則表示還有未除盡的余數,這個也是質因數,需要輸出

2、最小區間覆蓋

#include <iostream>

   using namespace std;

   const int MAXN = 5000;
   int n, m;
   struct segment { int a, b; } A[MAXN];

   void sort() // 排序
   {
     for (int i = 0; i < n; i++)
     for (int j = 1; j < n; j++)
     if (①)
         {
           segment t = A[j];
           ②
         }
   }

   int main()
   {
     cin >> n >> m;
     for (int i = 0; i < n; i++)
       cin >> A[i].a >> A[i]・b;
     sort();
     int p = 1;
     for (int i = 1; i < n; i++)
       if (③)
         A[p++] = A[i];
     n = p;
     int ans =0, r = 0;
     int q = 0;
     while (r < m)
     {
       while (④)
         q++;
       ⑤;
       ans++;
     }
     cout << ans << endl;
     return 0;
   }

【分析】相比第1題,本題作為壓軸題,更具難度,綜合考察了排序和貪心算法,以及綜合程序設計能力。
根據題目提示:使用貪心算法解決該問題,先將區間排序,然后使用貪心策略選擇區間。顯然該問題滿足貪心條件,可以使用貪心法求解。
每一個區間的起始值用結構體segment來描述,n個區間有segment類型的數組A來表示,為了能進行貪心選擇,首先需要按左端點進行排序,即對每個區間按a進行從小到大排序,依次排列,對應於sort函數,13-16行,這里采用的是冒泡排序。
1、A[j].a<A[j-1].a
2、A[j]=A[j-1];A[j-1]=t;
先比較,然后交換位置。
將0,m放在一條橫坐標上,則n個區間依次對應橫坐標上面的區間,依次排列起來,初始狀態如下所示:
在這里插入圖片描述
按左端點a排序好之后,如下圖所示
在這里插入圖片描述
這個時候就可以發現排好序后,有一些區間屬於無效區間,可以過濾掉,比如圖中灰色的區間,這些區間是這樣的一些區間,他們的右端點b值不大於其當前的前置區間的b值,很顯然,對於這樣的區間,其必然是其前置區間的子區間,所以只需保留其前置區間即可,其自身是多余的。26-30行,就是過濾掉這些無效區間的,p是過濾之后的剩余有效區間數,得到p值后,直接將其賦值給n,更新n值,代表當前有效待選區間的數量。
注意遍歷i從1~n-1,先從A[1]也就是第2個區間開始,逐個與A[0]比較,p初值為1,所以比較的是:
3、 A[i].b>A[p-1].b
滿足這樣條件的區間A[i]則將其保留為備選區間,保存在下標p的位置,然后p自增1,准備迎接下一個備選區間
A[p++] = A[i]

最后就是33行的while循環,開始在A[0]~A[p-1]這p個備選區間中進行選擇,按照貪心選擇思路,ans表示最終結果,r是當前已選區間覆蓋的最大范圍,q是當前已選區間的最大下標,初始未選擇任何區間,所以均值均為0。

循環開始,不斷選擇區間,每次選擇了一個區間,則ans自增1,同時更新r,然后繼續選擇,直到r達到m,結束。

     while (r < m)
     {
       while (④)
         q++;
       ⑤;
       ans++;
     }

在依次遍歷A[0]~A[p-1]時,要確定當前區間是否應該入選,按照貪心思想,則應該進可能選其后面的區間,因為后面的區間更靠近右端,因為前面已經排好序了,但是若要往后選,還需要滿足一個前提就是必須跟當前已選區間覆蓋的最大范圍也就是r要能銜接得上,也就是待選區間的a必須不大於當前的r,在滿足這個前提下,盡可能往后選擇。這對應於第4小題的while循環。
4、q+1<n&&A[q+1].a<=r
在這里插入圖片描述
如上圖所示,假設當前已經選擇了兩個區間,當前覆蓋范圍是r,q=2,依次檢測后續區間A[q+1],發現A[3],A[4],A[5],A[6]均滿足a<=r,到A[7]則不滿足了,所以此刻,A[3],A[4],A[5]則被pass調,q自增至6,所以應選最后一個滿足a<=r的A[6],然后ans加1,表示新選入了一個區間,同時更新r.

5、r=max(r,A[q].b)
本輪循環結束,然后進入下一輪遍歷,從A[7]開始。不斷選擇,直到最后r達到r時結束,此時輸出ans即最少的選擇區間數。

總評

CSP2020-J1整體難度與去年持平,難點依然集中在閱讀程序和完善程序的后面幾題,並且明顯難於比往屆NOIP普及組初賽試題,需要有較高的程序閱讀跟蹤能力和算法設計能力才能正確解答。盡管難度有提高,選擇題以及部分程序題屬於容易拿分的題目,比如質因數分解,字符串編解碼,進位次數統計等,這些容易拿分的題目保證高准確率,也能取得不錯的成績。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM