1030 完美数列(25)(25 分)

1030 完美数列(25)(25 分)

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

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

输入格式:

输入第一行给出两个正整数N和p,其中N(<= 10^5^)是输入的正整数的个数,p(<= 10^9^)是给定的参数。第二行给出N个正整数,每个数不超过10^9^。

输出格式:

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

输入样例:

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

输出样例:

8

完美数列 也就是 满足方程的最大覆盖数据中的数据个数。

思路 :

1. 先使得数据按照从小到大有序排序。

2.此时数据有序,这个时候遍历从 N-1号元素开始到 1 号元素结束,外部变量cnt记录覆盖的情况,如果此时的覆盖比上一次覆盖的个数要多就更新cnt否则就不更新。

3.传入 N-1号元素给子函数 计算最小满足方程的元素。子函数采用二分查找修改后的方法。定位最小范围 实现方法:

<< 找到范围中间的数判断是不是满足不等式,满足 移动 max的指针到这个元素,再动用二分修改查找,不满足,移动min指针到这个元素 再用二分修改查找 直到 二分值等于min所指元素的下标的时候 就break; 为什么?假设 min指针指向 1 号元素 max指针指向2号元素  (1+2)/2 是不是等于 1 如果这种情况不处理程序就会进入死循环。所以 一旦(类似) (1+2)/2 == min 那么就跳出。判断 min所指向元素是否满足方程 满足则返回 min元素的地址  否则由于前期的调整(红色处) 此时 max 所指向元素一定满足条件,返回max元素所指向元素的指针。>>(|||== 也就是说我尽量把 max指针指向可控范围,解答函数里做了一个判断 如果max都没有移动过 那么此次循环作废 一定不更新cnt)


好了 上代码吧 刚开始挺困扰我的 因为 一般思路是  排序   然后从这个元素 每一次都逐一往前遍历 找到范围,这样时间复杂度会比较高,此题还有部分不严谨的地方。在上完代码后会说一下:

#include <bits/stdc++.h>
using namespace std;
long long int a[100000 + 10];
int N, P;
long long int* efcz(int x) { // 位置
	int minst = 0;
	int maxst = x-1;
	if (maxst < minst) //       1  可以删除 永远不会发生越界访问 我上了三个保险 这个是 保险2
		return &a[minst];

	while (maxst>minst) { //    2   这个判断条件是多余的 可以等价于 while(1) 何况我对一个元素还是上了保险 1 控制越界
		int st = (maxst + minst) / 2;
		if (minst == st) {
			break;
		}
		else if (a[st] * P >= a[x]) {
			maxst = st;
		}
		else {
			minst = st;
		}
	}
	if(a[minst]*P>=a[x]) // 保险 3
		return &a[minst];
	return &a[maxst];
}

void solve() {

	scanf("%d%d", &N, &P);
	for (int i = 0; i<N; i++)
		scanf("%lld", &a[i]);
	sort(a, a + N);
	int cnt = 1;
	for (int i = N - 1; i > 0; i--) { // i>0是保险 1
		long long int* s = efcz(i);
		if (s != &a[i - 1]) {  //        3 测试系统忽略的错误  
			cnt = cnt<&a[i] - s + 1? &a[i] - s + 1 :cnt;
		}
	}
	printf("%d\n", cnt);

}

int main() {

	solve();
	return 0;
}

我认为题目的样例没有考虑到的:

1.这个情况题目也没有处理。就是一串数字所组成的所有数列之中 全部都不满足条件的情况 这个时候 二分的指针将会指向 数列最大值的前一项 这个时候 假定这个数也不满足条件 那么 如果没有3 就会出现 cnt由1变成2的错误情况

题目没有考虑到的样例1  这个是显然的错误。虽然我学C 才不到三个月 ~ 这种问题应该是显而易见才对。

5 2

1 11 111 1111 11111

应该输出 1  去掉 if输出 2  但是去掉if 答案依然是正确的。所以我怀疑题目样例出的不全。但是网上的答案这个样例我试的均输出正确了(hahahaha~~~)。但是这个和样例问题没有半毛钱关系~


必须要艰苦奋斗,才能看见阳光。现在虽然辛苦,但是必须承认也在成长。起步晚怎么了?每次被嘲笑,我已经要受够了!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值