P 1030 完美数列
转跳点:🐏
1030 完美数列 (25分)
给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列。
现在给定参数 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不易,诸君共勉!
大道五十,天衍四九,人遁其一!