[关闭]
@xiaoziyao 2021-08-03T10:52:55.000000Z 字数 1595 阅读 983

CF1285F Classical?解题报告

解题报告


CF1285F Classical?解题报告:

更好的阅读体验

题意

给定 个数,,求 。(

分析

并不好处理,考虑枚举 (设其为 ),取出满足条件的数(即 的倍数),那么我们要求的就是 的数对乘积最大值了。

我们发现取出所有数的复杂度是 时间的,所以我们可以直接取出所有数来判断。

我们将取出来的所有数除以 ,那么数对的 ,从大到小扫,设扫到了 ,如果之前有与它互素的数,那么仅有最大的那个数有用,且与它互素的数在后面一定没有用了。

这是一个很好的性质,考虑扫的时候怎么快速判断是否存在与它互素的数:

与它互素的数实在太多了,无法逐一枚举,但是所有数的因子总数却只有 级别,于是我们考虑每次只枚举每个数的因子。

具体地,我们发现可以容斥计算与 互素的数个数:(设 表示 的倍数出现次数)

加入一个数和删除一个数暴力算贡献,判断的时候就直接查,然后弹栈,这样的复杂度为

能不能再给力一点呢?

我们发现刚刚的方法只能处理 的情况,那么我们可以取出所有数的因子加入序列中,对于 最大的数对 ,它们的两个因子 ,满足,于是一定存在两个互素的数 仍为最大值。

时间复杂度:。(默认 与值域同阶)

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. using namespace std;
  4. const int maxn=100005;
  5. int n,maxx,top;
  6. int a[maxn],ok[maxn],cnt[maxn],miu[maxn],stk[maxn];
  7. long long ans;
  8. vector<int>d[maxn];
  9. int main(){
  10. scanf("%d",&n);
  11. for(int i=1;i<=n;i++)
  12. scanf("%d",&a[i]),ok[a[i]]=1,maxx=max(maxx,a[i]);
  13. ans=maxx,miu[1]=1;
  14. for(int i=1;i<=maxx;i++){
  15. for(int j=2*i;j<=maxx;j+=i){
  16. miu[j]-=miu[i],d[j].push_back(i);
  17. if(ok[j])
  18. ok[i]=1;
  19. }
  20. d[i].push_back(i);
  21. }
  22. for(int i=maxx;i>=1;i--){
  23. if(ok[i]==0)
  24. continue;
  25. int sum=0;
  26. for(int j=0;j<d[i].size();j++)
  27. sum+=miu[d[i][j]]*cnt[d[i][j]];
  28. while(sum>0){
  29. int dec=0;
  30. for(int j=0;j<d[stk[top]].size();j++){
  31. cnt[d[stk[top]][j]]--;
  32. if(i%d[stk[top]][j]==0)
  33. dec+=miu[d[stk[top]][j]];
  34. }
  35. if(dec)
  36. sum-=dec,ans=max(ans,1ll*i*stk[top]);
  37. top--;
  38. }
  39. for(int j=0;j<d[i].size();j++)
  40. cnt[d[i][j]]++;
  41. stk[++top]=i;
  42. }
  43. printf("%lld\n",ans);
  44. return 0;
  45. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注