CF1632D New Year Concert 题解
jiangtaizhe001 · · 题解
可能更好的阅读体验
题目传送门
这道题目很妙,而且可以写题解,所以就写了一片题解。
题目大意
定义一次操作位修改一个数组任意一位。
给定一个函数
现在给定一个长度为
数据范围:
题目解析
对于任意一个区间,如果左端点不变,右端点右移,那么这个区间内数字的最大公约数显然不增,这个区间的长度(也就是
我们可以用 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;
}