P 1030 完美数列

转跳点:🐏

 

1030 完美数列 (25分)
 

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 Mmp,则称这个数列是完美数列。

现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:

输入第一行给出两个正整数 N 和 p,其中 N(≤)是输入的正整数的个数,p(≤)是给定的参数。第二行给出 N 个正整数,每个数不超过 1。

输出格式:

在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

输入样例:

10 8
2 3 20 4 5 1 6 7 8 9
 

输出样例:

8

 

  这道题一开始我理解错了题意,觉得可以先排序,然后得到最大的数,然后计数在它前面有多少个数乘p大于等于它,这样只会在一个测试点得到WA,但是这还是过不了啊。后来,我才发现会有次大值大于最大值的完美数列……

  我AC的思路是:

  先对数组先进行排序,以样例为例子,排序完后,顺序为:1,2,3,4,5,6,7,8,9,20;

  那么选择array[0]为最小数,乘P,那么可以取的num的可以为1,2,3,4,5,6,7,8。一共有8个;

  假如进行第二次遍历,从array[1]开始,那么可以选择便有2,3,4,5,6,7,8,9,共有8个。

我们只需要这样遍历便可以得到最长的完美数列。

 

  但是要注意优化遍历,样例点4数据极其庞大,容易超时,

咱们第一遍跑的时候,1->8,停止,第二遍跑不进行优化的话又从0开始,这次多了个9 ,这一看就是一个O(N^2)的算法,而且重复很明显,1->8明显重复了n次,9重复了1次。

所以我们可以设置一个变量保存下每一次j最后一次的下标,供给下一次i循环使用,来减少重复。

  代码实现如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define MAXSIZE 100005
 4 #define MAX(a, b) ((a) > (b) ? (a) : (b)) //最大值的宏内联函数
 5 int cmp(void const *a, void const *b) { return (*(long *)a) > (*(long *)b) ? 1 : -1; }
 6 
 7 int main(void)
 8 {
 9     int num = 0;
10     long size, P;
11     long array[MAXSIZE];
12 
13     scanf("%ld %ld", &size, &P);
14 
15     for (int i = 0; i < size; i++)
16     {
17         scanf("%ld", &array[i]);
18     }
19     //升序
20     qsort(array, size, sizeof(array[0]), cmp);
21 
22     
23     int cnt = 0;
24     for (int i = 0; i < size; i++)
25     {
26         int j = cnt;                    //将前面算过的数全部屏蔽掉
27         while (j++ < size)
28         {
29             if (array[j] > array[i] * P)
30             {
31                 break;
32             }
33         }
34         num = MAX(num, j - i - 1);
35         cnt = j;
36     }
37 
38     printf("%d\n", num);
39 
40     return 0;
41 }

 

  C++代码在Github上自行转跳💞

 

PTA不易,诸君共勉!

posted @ 2020-01-14 00:14  秦_殇  阅读(209)  评论(0编辑  收藏  举报