CF1632D New Year Concert 题解
这道题目很妙,而且可以写题解,所以就写了一片题解。
题目大意
定义一次操作位修改一个数组任意一位。
给定一个函数 为对数组进行修改使得 使得 的操作数次数。
现在给定一个长度为 的整数序列 ,现在需要求 的值。
数据范围: 。
题目解析
对于任意一个区间,如果左端点不变,右端点右移,那么这个区间内数字的最大公约数显然不增,这个区间的长度(也就是 ) 增大。所以确定一个左端点之后,如果保证左端点 为定值,那么满足 最多只有 个。
我们可以用 ST 表求出满足 的所以有序整数对 。
然后不难发现一个引理:如果 满足 ,那么我们只需要在 之间任意修改一个数字就可以满足题目的条件了。
这样就成了线段覆盖问题,只需要按左端点从小到大排序(其实求出来的时候就是按照左端点从小大的所以不需要排序),然后每个区间尽量选择最右边的点即可。
核心代码:
int gcd(int x,int y){ if(!x) return y; if(!y) return x; return gcd(y,x%y); } int n,ln,a[maxn],st[20][maxn]; int l[maxn],r[maxn],cnt,nowgcd,nowr,ans[maxn],las,lasans; int main(){ n=read(); ln=log2(n); int i,j; for(i=1;i<=n;i++) a[i]=read(),st[0][i]=a[i]; for(j=1;j<=ln;j++) for(i=1;i<=n;i++) if(i+(1<<j)-1<=n) st[j][i]=gcd(st[j-1][i],st[j-1][i+(1<<(j-1))]); for(i=1;i<=n;i++){ nowgcd=a[i]; nowr=i; if(a[i]==1){ l[++cnt]=i; r[cnt]=i; continue; } for(j=ln;j>=0;j--) if(nowr+(1<<j)<=n&&gcd(nowgcd,st[j][nowr+1])>=nowr+(1<<j)-i+1) nowgcd=gcd(nowgcd,st[j][nowr+1]),nowr=nowr+(1<<j); if(nowgcd==nowr-i+1) l[++cnt]=i,r[cnt]=nowr; } for(i=1;i<=cnt;i++) if(l[i]>las){ ans[r[i]]=++lasans; las=mmax(las,r[i]); } for(i=1;i<=n;i++) ans[i]=mmax(ans[i],ans[i-1]),print(ans[i]),pc(' '); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具