题解 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\)。
但是这个正确性不好保证,所以笔者也只是放了一个猜想。这个问题先拿来用,但是笔者不会忘却这个猜想的证明的。
总结归纳
一个非常巧妙的题目。

浙公网安备 33010602011771号