Description
给定长度为 \(m\) 的数轴和起始位置 \(V\)。另外给定两个互质整数 \(A,B\)
每次操作可以从当前位置移动到 \(V\pm A\) 或者 \(V\pm B\) 但是不能超过数轴的边界 \([0,m]\)
求在进行任意多次操作之后的可达点数量
输入文件共 \(T\) 组数据
\(m\le 10^9,T\le 10^5\)
Solution
首先 \(A+B\le m+1\) 时答案是 \(m+1\)。注意到 \(A\perp B\) ,将从 \(V\) 走到某个位置 \(x\) 刻画成若干位移的合成,优先使用正位移,正位移无法使用的时候使用负位移即可
对于 \(A+B\ge m+2\) 的情况,进行完 \(+A\) 操作之后只能进行 \(+A/-B\) 操作,对于 \(+B\) 操作会超界,而 \(-A\) 操作不能走到之前没走过的位置。而 \(+A/-B\) 操作只能进行其中之一,那么能进行的操作形成了一条链
尝试考察同一条链中是否有重复经过某个点的情况出现,考察 最小 循环里面使用了 \(p\) 次 \(\pm A\),\(q\) 次 \(\pm B\) ,再根据 \(A\perp B\) 得到 \(A|p,B|q\),那么 \(p+q\ge A+B\ge m+2\) ,在这个过程中必然经过了重复的点。矛盾
再考察两条链之间是否有除了出发点 \(V\) 之外的交点,这显然没有,否则根据决策唯一性(前驱后继唯一)两条链将成为一条链。
此时两条链的边的数量之和 \(+1\) 就是能经过的总点数。
枚举 \(+A/+B\) 操作的总次数,两者做法一致,那么以 \(+A\& -B\) 为例。
枚举 \(+A\) 操作的操作数量 \(n\),\(-B\) 操作最多可以进行 \(\left\lfloor\dfrac{V+na}{B}\right\rfloor\)。那么要求的就是最小的 \(n\) 满足 \((V+nA)\bmod B+A>m\)
将其展开可以得到 \(\displaystyle M-(A-1)-V\bmod B \le nA\bmod B\le B-1-V\bmod B\) ,连续不等式首尾均为定值,那么可以将问题抽象成求 \(f(A,B,L,R)\) 表示求最小的 \(n\) 满足 \(L\le nA\bmod B\le R\)
这是常见问题,设 \(B=kA+c\) 并且设 \(qB\le nA<(q+1)B\) ,那么进行一些和式变换就可以得到子问题 \((-R)\le qr\mod A \le (-L)\)
当然如果区间已经包含 \(0\) 可以直接返回 \(\min q=0\) ,否则可以将 \(-L,-R\) 对 \(A\) 取模再递归
得到子问题 \(q\) 的最小值之后可以还原 \(n\) 的最小值 \(\left\lceil\dfrac{qB+L}A\right\rceil\)
时间复杂度 \(\Theta(T\log m)\)
这是不是类欧几里得呢?
Code
inline int get(int A,int B,int L,int R){
if(!A) return 0;
if((L-1)/A==R/A){
int q=get(B%A,A,(A-R%A)%A,(A-L%A)%A);
return (q*B+L+A-1)/A;
}
return (L+A-1)/A;
}
inline int calc(int A,int B,int V,int M){
int V0=V%B,p=0;
if(V0+A<=M) p=get(A,B,M-V0-(A-1),B-1-V0);
return p+(V+p*A)/B;
}
signed main(){
int T=read();
while(T--){
int A=read(),B=read(),V=read(),M=read();
if(A+B<=M+1){
print(M+1);
continue;
}
print(calc(A,B,V,M)+calc(B,A,V,M)+1);
}
return 0;
}