题解 luogu.P1414 又是毕业季II

题目

luogu.P1414 又是毕业季II

题意建模

主要是说一下这个代码的细节

算法分析

还是“贡献观点”。也就是考一个桶来记录一个数出现的次数。但是代码实现非常精巧,用到了一个小小的性质,当然这些内容我们在后文的细节研讨中会详细分析的。我们还是梳理以下这个题的思路:

  • 维护一个最大值;
  • 找出若干个数的因数,并看看出现了多少次(这就是桶的作用之一);
  • 循环枚举每一个 \(k\),对于一个 \(k\),如果这个值越大,说明其范围内公因数出现的最大值会越小。(至于是为什么,暂且按下不表)。

参考代码

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e6+5;
int ans,t[N],max_val; 
int main()
{
	int n; scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x; scanf("%d",&x);
		max_val=max(max_val,x);
		
		for(int j=1;j<=x/j;j++)
			if(x%j==0) 
			{
				t[j]++;
				if(x/j!=j) t[x/j]++;
			}
	}
	int x=max_val;
	for(int i=1;i<=n;i++)
	{
		while(t[x]<i) x--;
		printf("%d\n",x);
	}
	return 0;
}

细节实现

我们来看看上面说的这个小小的性质,这就使得代码可以简洁地写出来。为了用词精确,并且表意到位,容许笔者这里引用一下出题人的原话:

每个数分解因数,\(c[i]\) 表示 \(i\) 作为因子的次数。 对于答案 \(i\)\(c[x]>i\)\(p\) 可以作为答案。
可以发现 \(i\) 的答案一定大于等于 \(i+1\)的答案。
扫一遍找答案行了。

笔者这里将重要的信息加粗了。这个性质不好证明,唯一可以稍作解释的是整数的离散型,这就保证了,如果出现的数字越多,那么从概率上讲,这些数字的 \(\gcd\) 会越来越小,直到变成 \(1\)

但是这个正确性不好保证,所以笔者也只是放了一个猜想。这个问题先拿来用,但是笔者不会忘却这个猜想的证明的。

总结归纳

一个非常巧妙的题目。

posted @ 2025-08-04 09:22  枯骨崖烟  阅读(8)  评论(0)    收藏  举报