greenmint

导航

新光一2026-04-04 T2 P1414

P1414 又是毕业季II

题目背景

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

题目描述

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

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

输入格式

第一行一个正整数 \(n\)

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

输出格式

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

输入输出样例 #1

输入 #1

4
1 2 3 4

输出 #1

4
2
1
1

说明/提示

【题目来源】

lzn 原创

【数据范围】

记输入数据中能力值的最大值为 \(\textit{inf}\)

  • 对于 \(20\%\) 的数据,\(n \leq 5\)\(\textit{inf}\leq 10^3\)
  • 对于另 \(30\%\) 的数据,\(n \leq 100\)\(\textit{inf} \leq 10\)
  • 对于 \(100\%\) 的数据,\(n \leq 10^4\)\(\textit{inf} \leq 10^6\)

思路

一、先看懂题目核心需求
题目简化:
给定 n 个数,对 k=1,2,...,n 分别输出:
从 n 个数里选 k 个数,它们的最大公约数的最大值。
示例:4 个数 [1,2,3,4]
k=1:选最大数 4 → gcd=4
k=2:选 2、4 → gcd=2
k=3:任意 3 个数,最大 gcd=1
k=4:全部选,gcd=1

二、整体解题思路(核心思想)
这道题不能暴力枚举(n=1e4,暴力会超时),正确做法是:
逆向思维:枚举公约数,统计能被它整除的数有多少个
统计每个数字出现的次数
对每个数 d,统计有多少个数是 d 的倍数 → 这个数量就是:最多能选 cnt[d] 个人,让他们的 gcd 至少是 d
最后处理答案:对每个 k,找到最大的 d 满足 cnt[d] ≥ k

时间复杂度O(\(inf\)\(log\)\(inf\))
inf=1e6,完全能通过题目限制
空间复杂度:
O(1e6)
,数组大小合规
思路简洁:筛法统计 + 倒推答案,是这道题的标准最优解法

本题核心是逆向枚举公约数 + 筛法统计,避免暴力超时
cnt[d] 表示有多少个数可以被 d 整除,即最多选 cnt[d] 人
倒序更新答案是为了让小 k 继承大 k 的最优解

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,mx,cnt[N],ans[N];
int main(){
    cin>>n;
    for(int i=0,x;i<n;i++){cin>>x;cnt[x]++;mx=max(mx,x);}
    for(int i=1;i<=mx;i++)
        for(int j=i*2;j<=mx;j+=i)
            cnt[i]+=cnt[j];
    for(int i=1;i<=mx;i++)ans[cnt[i]]=max(ans[cnt[i]],i);
    for(int i=n-1;i>=1;i--)ans[i]=max(ans[i],ans[i+1]);
    for(int i=1;i<=n;i++)cout<<ans[i]<<'\n';
    return 0;
}

posted on 2026-04-08 10:05  绿萝薄荷叶  阅读(4)  评论(0)    收藏  举报