CF1632D New Year Concert 题解

可能更好的阅读体验
题目传送门

这道题目很妙,而且可以写题解,所以就写了一片题解。

题目大意

定义一次操作位修改一个数组任意一位。
给定一个函数 f(b1,b2,,bn) 为对数组进行修改使得 l,r[1,n] 使得 gcd(al,al+1,,ar)rl+1 的操作数次数。
现在给定一个长度为 n 的整数序列 a,现在需要求 f(a1)+f(a1+a2)++f(a1,a2,,an) 的值。
数据范围: 1n2×105,1ai109

题目解析

对于任意一个区间,如果左端点不变,右端点右移,那么这个区间内数字的最大公约数显然不增,这个区间的长度(也就是 rl+1) 增大。所以确定一个左端点之后,如果保证左端点 l 为定值,那么满足 gcd(al,al+1,,ar)=rl+1 最多只有 1 个。
我们可以用 ST 表求出满足 gcd(al,al+1,,ar)=rl+1 的所以有序整数对 (l,r)

然后不难发现一个引理:如果 l,r 满足 gcd(al,al+1,,ar)=rl+1,那么我们只需要在 l,r 之间任意修改一个数字就可以满足题目的条件了。
这样就成了线段覆盖问题,只需要按左端点从小到大排序(其实求出来的时候就是按照左端点从小大的所以不需要排序),然后每个区间尽量选择最右边的点即可。

核心代码:

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;
}
posted @   jiangtaizhe001  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示