[蓝桥杯][2018年第九届真题]倍数问题(贪心+思维)

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

输入
从标准输入读入数据。

第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。
输出
输出到标准输出。
输出一行一个整数代表所求的和。
样例输入
4 3
1 2 3 4
样例输出
9
提示
对于 30% 的数据,n <= 100。
对于 60% 的数据,n <= 1000。
对于另外 20% 的数据,K <= 10。
对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。
思路:因为k只有1e3的数据量,因此我们可以从k入手。我们先按照每个数对k取余的数字将每个数字分类。然后两重循环枚举0~k-1,这样就可以求第三个数字。然后不对的更新最大值就可以了。
代码如下:

#include
#define ll long long
using namespace std;

const int maxx=1e5+100;
const int maxm=1e3+100;
int a[maxx];
vector<int> p[maxm];
int n,k;

bool cmp(int a,int b){
     return a>b;}
int main()
{
     
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
     
		scanf("%d",&a[i]);
		p[a[i]%k].push_back(a[i]);
	}
	for(int i=0;i<k;i++) sort(p[i].begin(),p[i].end(),cmp);
	int _max=0;
	for(int i=0;i<k;i++)
	{
     
		if(p[i].size()==0) continue;
		if((3*i==k||i==0)&&p[i].size()>=3) _max=max(_max,p[i][0]+p[i][1]+p[i][2]);
		for(int j=0;j<k;j++)
		{
     
			if(!p[j].size()) continue;
			int z=k-(i+j)%k;//!!这里要注意。
			if(z<0) continue;
			if(z==i&&z==j) continue;
			else if((i!=j)&&(z==i||z==j)&&p[z].size()>=2) _max=max(_max,p[i][0]+p[j][0]+p[z][1]);
			else if(i==j&&p[i].size()>=2&&p[z].size()>=1) _max=max(_max,p[i][0]+p[j][1]+p[z][0]);
			else if(i!=j&&i!=z&&j!=z&&p[i].size()>=1&&p[j].size()>=1&&p[z].size()>=1) _max=max(_max,p[i][0]+p[j][0]+p[z][0]); 
		}
	}
	printf("%d\n",_max);
	return 0;
}

努力加油a啊,(o)/~

你可能感兴趣的:(贪心,思维)