万欧学习笔记
淦,学习笔记一直咕咕咕,咕的忘记咋做了/ll
已经不知道咕了几篇学习笔记了
pb 大师写的易懂博客(但是我就是要再抄一遍!)
万能欧几里得确实挺万能的,可以解决形如下述的问题(其实有缺陷):
给定一条直线 \(y=\frac{px+r}{q} \quad (p,q>0,r \ge 0)\) ,我们在 \(x\in(0,l]\) 上从左往右扫描,若当前 \(y=k \quad (k \in \mathbb{Z})\) 则给操作序列加上一个操作 \(U\) ,然后若当前 \(x=k \quad(k \in \mathbb{Z})\) 则给操作序列加个操作 \(R\)
如果操作 \(U\) 和 \(R\) 满足结合律,那么就可以万能欧几里得
为了更好的约束问题,若 \(r \ge q\) ,则直接将多出的 \(\lfloor \frac{r}{q} \rfloor\) 个 \(U\) 操作加在最前面,然后只需处理 \(r \bmod q\) 的问题了
我们记上面这个问题的答案操作序列为 \(solve(p,r,q,l,U,R)\) ,分为两种情况来讨论
若 \(p \ge q\) ,则一个 \(R\) 操作之前必然有 \(\lfloor \frac{p}{q} \rfloor\) 个 \(U\) 操作,我们令 \(R'=U^{\lfloor \frac{p}{q} \rfloor}R\) ,然后计算 \(solve(p \bmod q,r,q,l,U,R')\) 即可
若 \(p<q\) ,我们试图将 \(p\) 和 \(q\) 交换一下,这样就可以转换到第一步然后获得优秀的复杂度
首先把没有 \(U\) 操作的平凡情况去掉
可以发现第 \(a\) 个 \(R\) 操作之前有 \(\lfloor \frac{pa+r}{q} \rfloor\) 个 \(U\) 操作,如果第 \(b\) 个 \(R\) 操作在其之后,则需满足
推一推,我们的目的是将 \(a\) 用 \(b\) 表示
这样第 \(i\) 个 \(U\) 操作前就有 \(\lfloor \frac{qi-r-1}{p} \rfloor\) 个 \(R\) 操作了,和原问题等价...了吗?
如果这样的话 \(r'=-r-1\) ,不满足原问题的条件了!所以我们考虑把第一个 \(U\) 操作和之前的 \(R\) 操作直接处理出来,观察此时的 \(r'\)
可以发现删去之后的第 \(i\) 个与第 \(i-1\) 个 \(U\) 操作之间有 \(\lfloor \frac{q(i+1)-r-1}{p} \rfloor-\lfloor \frac{qi-r-1}{p} \rfloor=\lfloor \frac{qi+q-r-1}{p} \rfloor-\lfloor \frac{q(i-1)+q-r-1}{p} \rfloor\) 个 \(R\) 操作
可能觉得 \(r'=q-r-1\) ?不!因为注意到我们原本已经删除的第一个 \(U\) 操作前的 \(R\) 操作算过了,所以 \(r'=(q-r-1) \bmod p\)
然后再观察一下 \(l'\) 就是原来 \(U\) 的操作数减 \(1\) (减 \(1\) 是因为忽略了第一个 \(U\) ),也就是 \(l'=\lfloor \frac{pl+r}{q} \rfloor-1\) ,然后最后的 \(U\) 后面还剩了几个 \(R\) 需要加上,所以可以得到
可以发现因为有结合律,故 \(U^k\) 或 \(R^k\) 都可以 \(O(c \log k)\) 的计算( \(O(c)\) 是合并两个操作花的时间),随便推推可以发现总复杂度为 \(O(c \log \max(p,q))\)
反正各种题的 \(solve\) 几乎没区别,贴一份通用代码(这里默认 \(r<q\) ):
点击查看代码
#define ll long long
inline ll Div(ll p,ll x,ll r,ll q){
return ((__int128)x*p+r)/q;
}
D solve(ll p,ll r,ll q,ll l,D U,D R){
if(!l)return D();
if(p>=q)return solve(p%q,r,q,l,U,qmul(U,p/q)+R);
ll lc=Div(p,l,r,q);
if(!lc)return qmul(R,l);
return qmul(R,(q-r-1)/p)+U+solve(q,(q-r-1)%p,p,lc-1,R,U)+qmul(R,l-Div(q,lc,-r-1,p));
}
好像大部分例题都有详细的题解了,这里就不写了