Examples

ARC127F ±AB 解题报告

ARC127F ±AB 解题报告:

题意

给定 \(a,b\)(保证互素),有一个变量 \(x\) 初始为 \(V\),你可以执行以下操作:

\[x\leftarrow x+a,x\leftarrow x-a\\x\leftarrow x+b,x\leftarrow x-b \]

你只需保证操作时 \(0\leqslant x\leqslant m\),求你能得到多少个不同的 \(x\)

\(q\) 次询问。

\(1\leqslant q\leqslant 10^5,1\leqslant a,b,V\leqslant m\leqslant 10^9\)

分析

模拟赛场上两个人做出来了,其中有一个才新初二,只能说广二真恐怖。

先尝试利用裴蜀定理遍历每一个数,若区间长度大于等于 \(a+b\),我们可以持续进行 \(+a,-b\) 操作(两种操作一定有一个能进行),容易发现可以遍历每一个数字。

否则 \(a+b>m+1\)

若第一步为 \(+a\),那么下一步不能为 \(+b\),也不能为 \(-a\)(没有意义),而 \(+a,-b\) 中最多只有一种合法,于是后面的方案已然确定。

第一步为 \(+b\) 时同理,我们观察这两条链可以得到两条性质:

  • 链不存在循环,因为最小循环节 \(a+b>m+1\)
  • 两条链不会相交,显然。

于是我们只需计算“不断进行 \(+a,-b\) 操作,能执行多少次”。

其等价于找到最小的 \(k\) 使得 \((V+ak)\bmod b>m-a\)

\(V_0=V\bmod b\),特判 \(V_0+a>m\) 的情况。

现给出如下结论:

\[V_0+(ak\bmod b)=(V+ak)\bmod b \]

只需说明 \(V_0+(ak\bmod b)<b\)

\(V_0+(ak\bmod b)\geqslant b\),则有 \(V_0+a+(ak\bmod b-b)\leqslant V_0+a\leqslant m\)。我们可以到达 \(V_0+(ak\bmod b-b)\) 后进行一次 \(+a\) 操作,矛盾。

于是问题变为找到最小的 \(k\) 使得满足:

\[m-a-V_0<ak\bmod b<b-V_0 \]

这是经典的类欧几里得算法,我们将其泛化为“找到最小的 \(k\) 满足 \(ak\bmod b\in[L,R]\)”。

\(b=ap+q,t=\lfloor\frac{ak}{b}\rfloor\),则有:

\[ak-tb\in[L,R]\\ \Rightarrow a(k-tp)-tq\in[L,R]\\ \Rightarrow tq\bmod a\in[L',R']\]

此时问题由 \((a,b)\) 转化为了 \((b\bmod a,a)\),只需递归 \(\log\) 层即可使得 \(a=0\),直接计算即可。

复杂度 \(O(q\log m)\)

代码

#include<stdio.h>
int T,a,b,v,m;
int Euclid(int a,int b,int l,int r){
	if(a==0)
		return 0;
	a%=b;
	if((l-1)/a!=r/a)
		return (l+a-1)/a;
	int t=Euclid(b%a,a,(a-r%a)%a,(a-l%a)%a);
	return (1ll*t*b+l+a-1)/a;
}
int calc(int a,int b,int v,int m){
	int v0=v%b;
	if(v0+a>m)
		return v/b;
	int k=Euclid(a,b,m-a-v0+1,b-v0-1);
	return k+(v+1ll*a*k)/b;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d%d",&a,&b,&v,&m);
		if(a+b<=m+1)
			printf("%d\n",m+1);
		else printf("%d\n",calc(a,b,v,m)+calc(b,a,v,m)+1);
	}
	return 0;
}
posted @ 2022-09-06 17:43  xiaoziyao  阅读(65)  评论(0编辑  收藏  举报