。。。倍。数。问。题。桶排序,三重循环优化二重循环--第几个幸运数字--2018lqb

问题描述

  众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

输入格式

  从标准输入读入数据。

  第一行包括 2 个正整数 n, K。
  第二行 n 个正整数,代表给定的 n 个数。

输出格式

  输出到标准输出。
  输出一行一个整数代表所求的和。

样例入

  4 3
  1 2 3 4

样例输出

9

样例说明

  选择2、3、4。

数据约定

  对于 30% 的数据,n <= 100。
  对于 60% 的数据,n <= 1000。
  对于另外 20% 的数据,K <= 10。
  对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。


  资源约定:
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 1000ms


  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

  注意:
  main函数需要返回0;
  只使用ANSI C/ANSI C++ 标准;
  不要调用依赖于编译环境或操作系统的特殊函数。
  所有依赖的函数必须明确地在源文件中 #include
  不能通过工程设置而省略常用头文件。

  提交程序时,注意选择所期望的语言类型和编译器类型。

显然,对于输入的n个数,利用对k取余得到的余数,获得k个桶,将n个数分为k类,由于只要三个数的最大和,那么每个桶维护三个最大的数即可;求最大和,三个数,三重循环,由于求最大值,且每个桶中的数是有序的,所以,前两个数确定了,枚举前两个数之后,第三个数就可以唯一确定了,转换为二重循环。实际就是桶排序加模拟。

#include 
#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
using namespace std;
int n, k;
int group[1010][3];
int ans = 0;
int main() {
	cin >> n >> k;
	int res;
	//直接分组
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;//接受输入的值
		res = x % k;//数x是属于桶res的
		if (x > group[res][0]) {//x应该是当前桶中最大的数--移动
			group[res][2] = group[res][1];
			group[res][1] = group[res][0];
			group[res][0] = x;
		}
		else {
			if (x > group[res][1]) {//x应该是当前桶中第二大的数--移动
				group[res][2] = group[res][1];
				group[res][1] = x;
			}
			else
				if (x > group[res][2]) {//x应该是当前桶中第三大的数--移动
					group[res][2] = res;
				}
		}	
	}
	//k在1000以内
	//模拟
	//取三个数的过程
	//三层循环---在和最大值的约束下,确定了前两个数,则第三个数唯一确定
	//暴力枚举前两个数即可
	//模拟从k个桶中取三个数的过程
	int v1, v2, v3;
	int z;//记录第三个数所在的桶
	for (int i = 0; i < k; i++) {//枚举第一个数所在的桶
		v1 = group[i][0];
		if (v1 != 0) {
			for (int j = 0; j < k; j++) {//枚举第二个数所在的桶
				if (i == j)
					v2 = group[i][1];
				else
					v2 = group[j][0];
				if (v2 != 0) {
					//第二个数是有效的---前两个数确定后,第三个数是唯一确定的,
					//下面找到在当前两个数的情况下,哪个第三个数使和最大 z的设置,使循环由三重简化为二重
					z = (k - (i + j) % k) % k;
					if (i == j) {//前两个数取自一个桶
						if (z == i)//第三个数在桶i中
							v3 = group[i][2];
						else//第三个数在非i非j桶中
							v3 = group[z][0];
					}
					else//前两个数不是取自同一个桶
					{
						if (z == i)//第三个数在桶i中
							v3 = group[i][1];
						else
							if (z == j)//第三个数在桶j中
								v3 = group[j][1];
							else
								v3 = group[z][0];//第三个数在非i非j桶中
					}
					if (v3 != 0)//第三个数是有效的--三个数成功取出
						ans = max(v1 + v2 + v3, ans);
				}
			}
		}
	}
	cout << ans << endl;
	return 0;
}

 第几个幸运数字

到x星球旅行的游客都被发给一个整数,作为游客编号。
x星的国王有个怪癖,他只喜欢数字3,5和7。
国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。
前10个幸运数字是:3 5 7 9 15 21 25 27 35 45,因而第11个幸运数字是:49
小明领到了一个幸运数字 59084709587505。
去领奖的时候,人家要求他准确说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505是第几个幸运数字。

个人感觉类似上面的题目

暴力枚举,每次步长不要设置为1,那样是运行不出来结果的

题目都说了,因数只有3/5/7,那么就用次方去枚举

如下---注意1的特殊性,最后要减去1这种情况(1满足枚举的情况,但不满足提议,要是枚举时不从1开始, 会漏去很多情况)

#include 
#include
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int gcd(int a, int b) {
	while (a != b) {
		if (a > b)
			a = a - b;
		else
			b = b - a;
	}
	return a;
}
int main()
{
	//long long n = 59084709587505;
	int ans = 0;
	//计算因数2和5的个数
	///*for (long long j = 3; j <= 59084709587505; j++) {
	//	long long n = j;
	//	int count3 = 0, count5 = 0, count7 = 0;
	//	if (n % 3 != 0 && n % 5 != 0 && n % 7 != 0)continue;
	//	while (n % 3 == 0) {
	//		count3++;
	//		n /= 3;
	//	}
	//	while (n % 5 == 0) {
	//		count5++;
	//		n /= 5;
	//	}
	//	while (n % 7 == 0) {
	//		count7++;
	//		n /= 7;
	//	}
	//	if(n == 1)
	//		ans++;
	//}*/
	int i, j, k;
	long long x = 59084709587505;
	for (i = 0; pow(3, i) <= x; i++)
		for (j = 0; pow(5, j) <= x; j++)
			for (k = 0; pow(7, k) <= x; k++)
			{
				if (pow(3, i) * pow(5, j) * pow(7, k) <= x)
				{
					ans++;
				}
			}
	printf("%d", ans - 1);//其中i,j,k都为0时不符合要求,要减去1
	//cout << ans << endl;//1905 1906
	return 0;
}

你可能感兴趣的:(职场和发展)