算法复健ing
原题链接:https://codeforces.com/contest/1732/problem/E
大意:给定长度为n的数组a与b,有两种操作,为a区间赋值x,区间最值查询,需要维护的是a[i]*b[i]/gcd(a[i],b[i])/gcd(a[i],b[i])的最值
题解:
先从暴力入手,暴力修改,暴力询问,时间复杂度为O(qN),时间复杂度为O(3e9*log)
但注意,区间赋值时,赋的值都是相同的,故容易联想到分块操作,离散块暴力修改,区间块使用tag修改
假设块长为k,则我们获得了n/k个块,接下来考虑如何维护对各个块的询问
对于离散块,暴力修改,并记录修改后的值是否为最值
由于能赋的值范围较小,对于整块,我们对每个块维护一个ans[k],为当前块都被赋成k值时,当前块的答案.
对于给定的k,我们遍历k的所有约数,对于所有约数,寻找最小的b[i],能被该约数整除(即先假定该约数是gcd,当gcd一定时,b[i]越小,其代表的答案越小),遍历所有的约数后,记录最小答案的位置为i
证明该最小答案的正确性:假设k的两个约数d1,d2均能整除某个b[i],则其中较大者一定是更优答案,且一定会被遍历到.即最终取得的一定是最优情况
这里写法有个小trick,直接for(int i=1;i<=MAX;i++),约数放在外面,然后for(int k=i;k<=MAX;k+=i),复杂度为MAX(logMAX);同时用个vis数组标记当前块中是否存在b[i]=k,若存在,则直接取符合条件的最小的b[i]去更新答案
1 |
|
注意:用了nb版本的gcd,否则狂T
两种gcd时间对比