@xiaoziyao
2021-08-03T02:52:55.000000Z
字数 1595
阅读 1372
解题报告
CF1285F Classical?解题报告:
给定 个数,,求 。()
并不好处理,考虑枚举 的 (设其为 ),取出满足条件的数(即 的倍数),那么我们要求的就是 为 的数对乘积最大值了。
我们发现取出所有数的复杂度是 时间的,所以我们可以直接取出所有数来判断。
我们将取出来的所有数除以 ,那么数对的 为 ,从大到小扫,设扫到了 ,如果之前有与它互素的数,那么仅有最大的那个数有用,且与它互素的数在后面一定没有用了。
这是一个很好的性质,考虑扫的时候怎么快速判断是否存在与它互素的数:
与它互素的数实在太多了,无法逐一枚举,但是所有数的因子总数却只有 级别,于是我们考虑每次只枚举每个数的因子。
具体地,我们发现可以容斥计算与 互素的数个数:(设 表示 的倍数出现次数)
加入一个数和删除一个数暴力算贡献,判断的时候就直接查,然后弹栈,这样的复杂度为 。
能不能再给力一点呢?
我们发现刚刚的方法只能处理 的情况,那么我们可以取出所有数的因子加入序列中,对于 最大的数对 ,它们的两个因子 ,满足,于是一定存在两个互素的数 仍为最大值。
时间复杂度:。(默认 与值域同阶)
#include<stdio.h>#include<vector>using namespace std;const int maxn=100005;int n,maxx,top;int a[maxn],ok[maxn],cnt[maxn],miu[maxn],stk[maxn];long long ans;vector<int>d[maxn];int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),ok[a[i]]=1,maxx=max(maxx,a[i]);ans=maxx,miu[1]=1;for(int i=1;i<=maxx;i++){for(int j=2*i;j<=maxx;j+=i){miu[j]-=miu[i],d[j].push_back(i);if(ok[j])ok[i]=1;}d[i].push_back(i);}for(int i=maxx;i>=1;i--){if(ok[i]==0)continue;int sum=0;for(int j=0;j<d[i].size();j++)sum+=miu[d[i][j]]*cnt[d[i][j]];while(sum>0){int dec=0;for(int j=0;j<d[stk[top]].size();j++){cnt[d[stk[top]][j]]--;if(i%d[stk[top]][j]==0)dec+=miu[d[stk[top]][j]];}if(dec)sum-=dec,ans=max(ans,1ll*i*stk[top]);top--;}for(int j=0;j<d[i].size();j++)cnt[d[i][j]]++;stk[++top]=i;}printf("%lld\n",ans);return 0;}
