【Luogu1414】又是毕业季II(数论)

【Luogu1414】又是毕业季II(数论)

题面

题目背景

“叮铃铃铃”,随着高考最后一科结考铃声的敲响,三年青春时光顿时凝固于此刻。毕业的欣喜怎敌那离别的不舍,憧憬着未来仍毋忘逝去的歌。1000多个日夜的欢笑和泪水,全凝聚在毕业晚会上,相信,这一定是一生最难忘的时刻!
题目描述

彩排了一次,老师不太满意。当然啦,取每位同学的号数来找最大公约数显然不太合理。于是老师给每位同学评了一个能力值。于是现在问题变为,从n个学生中挑出k个人使得他们的默契程度(即能力值的最大公约数)最大。但因为节目太多了,而且每个节目需要的人数又不知道。老师想要知道所有情况下能达到的最大默契程度是多少。这下子更麻烦了,还是交给你吧~

PS:一个数的最大公约数即本身。

输入输出格式

输入格式:

第一行一个正整数n。

第二行为n个空格隔开的正整数,表示每个学生的能力值。

输出格式:

总共n行,第i行为k=i情况下的最大默契程度。

输入输出样例

输入样例#1:

4
1 2 3 4

输出样例#1:

4
2
1
1

题解

这道题目比较好。。。
那道“又是毕业季I”是道傻逼题
这道题目比较好呀。
如果考虑枚举GCD判断个数,这显然是逃不过(O(inf*n))的复杂度的
现在换个方式来看,我们可以把所有的约数的出现次数提前算出来,
最后依次检查是否最大即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 10100
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
int a[MAX],mm,n,vv[MAX<<7];
int ans[MAX];
int main()
{
	n=read();
	for(int i=1;i<=n;++i)a[i]=read();
	for(int i=1;i<=n;++i)
	{
		for(int j=1,l=sqrt(a[i]);j<=l;++j)
			if(a[i]%j==0)
			{
				vv[j]++;
				if(a[i]!=j*j)
					vv[a[i]/j]++;
			}
	}
	for(int i=1000000;i;--i)
		ans[vv[i]]=max(ans[vv[i]],i);
	for(int i=n;i;i--)ans[i]=max(ans[i+1],ans[i]);
	for(int i=1;i<=n;++i)
		printf("%d
",ans[i]);
	return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/7798902.html