Codeforces1285F Classical?
Description
给定长度为 的数列 ,求
Solution
先转化成乘积除以 的形式,枚举 并提取出来所有是该数倍数的数,下面叙述中的 都表示除过 得到的结果
从小到大枚举每个元素并将其设为 ,也就是说在被提取出来的所有数字中找到的最大的小于它的且和它互质的数
如果想要判定一些数字和某个数字 是不是互质,可以通过 来处理:
设 表示 的倍数在被提取出来的数字除 出现了多少次
先计算 再二分找到最大的前缀满足只考虑该前缀在桶里面的贡献仍然可以得到
不难发现还要把桶可持久化所以复杂度太高了
通过从大到小枚举来减少冗余计算量,如果某个 找到最大的 满足 ,那么 的所有 在后续计算中将不被需要
那么维护一个栈以及和上面类似的桶,先算一次 得到互质元素数量,再直接弹栈到不再存在互质元素即可
复杂度到了 但是还可以更优!
对于最优解 那么一定存在一组 且 那么直接将每个数字的存在性表示为其所有倍数存在性的 或 结果,直接做 的部分即可
时间复杂度
Code
const int N=1e5+10;
int stk[N],top;
int n;
bool a[N],isc[N];
int mu[N],pri[N],cnt;
vector<int> Div[N];
int ton[N];
signed main(){
n=1e5; mu[1]=1;
for(int i=2;i<=n;++i){
if(!isc[i]) pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&pri[j]*i<=n;++j){
isc[i*pri[j]]=1;
if(i%pri[j]==0){
mu[i*pri[j]]=0;
break;
}else mu[i*pri[j]]=-mu[i];
}
}
n=read();
for(int i=1;i<=n;++i) a[read()]=1;
for(int i=1e5;i>=1;--i){
for(int j=i;j<=1e5;j+=i){
a[i]|=a[j];
Div[j].emplace_back(i);
}
}
int ans=0;
for(int i=1e5;i>=1;--i) if(a[i]){
ckmax(ans,i);
int num=0;
for(auto t:Div[i]) num+=ton[t]*mu[t];
while(num){
if(gcd(i,stk[top])==1) --num,ckmax(ans,i*stk[top]);
for(auto t:Div[stk[top]]) --ton[t];
--top;
}
for(auto t:Div[i]) ton[t]++;
stk[++top]=i;
}
print(ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律