编程语言
首页 > 编程语言> > CSP2020-J1-真题解析-完善程序

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普及组初赛试题,需要有较高的程序阅读跟踪能力和算法设计能力才能正确解答。尽管难度有提高,选择题以及部分程序题属于容易拿分的题目,比如质因数分解,字符串编解码,进位次数统计等,这些容易拿分的题目保证高准确率,也能取得不错的成绩。

标签:真题,int,CSP2020,J1,++,while,ans,区间,贪心
来源: https://www.cnblogs.com/HustJackyan/p/14883600.html