EXGCD
用于解形如ax+by=gcd(a,b)方程的通解
1 2 3 4 5 6 7 8 9 10 11 12 13
| void exgcd(int &x,int &y,int a,int b) { if(!b) { x=1; y=0; return; } exgcd(x,y,b,a%b); int t=x; x=y; y=t-a/b*y; }
|
也可以解出ax+by=c gcd(a,b)|c的解
上方参数还是gcd(a,b) 解出后x2=x*c/gcd(a,b) y2=y*c/gcd(a,b)
通解为:
{(x, y) | x = x2 + k * b / gcd(a, b), y = y2 - k * a / gcd(a, b), k ∈ z}
特别的 gcd(a,b)等于1时
相当于求ax=1(modb) 为a在b下的逆元(不用b是质数) 解出x后用 x=(x%b+b)%b求出在0-b范围内的x即为逆元
类欧几里得
当我们要计算形如
i=0∑n⌊cai+b⌋
且a,b>=0,c>0时
可以使用类欧算法。
首先有以下公式
⌈ba⌉=⌊ba+b−1⌋
⌊ba⌋=⌈ba−b+1⌉
挺容易推的:关于1式,如果 a % b != 0,那么右边就会比左边大1,2式原理相同。
然后开始推(?
我们令
F(a,b,c,n)=i=0∑n⌊cai+b⌋
a≥c⇒i=0∑n⌊cai+b⌋=i=0∑n(⌊ca%c×i+b⌋+⌊ca⌋i)=i=0∑n⌊ca%c×i+b⌋+⌊ca⌋2n×(n+1)
b≥c⇒i=0∑n⌊cai+b⌋=i=0∑n⌊cai+b%c⌋+⌊cb⌋(n+1)
因此
a≥c∣∣b≥c⇒i=0∑n⌊cai+b⌋=i=0∑n⌊c(a%c)i+b%c⌋+⌊cb⌋(n+1)+⌊ca⌋2n×(n+1)
⇒F(a,b,c,n)=F(a%c,b%c,c,n)++⌊cb⌋(n+1)+⌊ca⌋2n×(n+1)
之后只要解决a<c&&b<c的情况就好了(?
由
i=0∑n⌊cai+b⌋=i=0∑nj=1∑⌊cai+b⌋1=i=0∑nj=1∑⌊can+b⌋[j≤⌊cai+b⌋]
交换求和顺序(
⇒j=1∑⌊can+b⌋i=0∑n[j≤⌊cai+b⌋]
又有
⌊ba⌋≥c⇔a≥bc
⌈ba⌉≤c⇔a≤bc
因此
=j=1∑⌊can+b⌋i=0∑n[jc≤ai+b]=j=1∑⌊can+b⌋i=0∑n[⌈ajc−b⌉≤i]=j=1∑⌊can+b⌋[n+1−⌈ajc−b⌉]
=j=1∑⌊can+b⌋[n+1−⌊ajc−b+a−1⌋]
=n⌊can+b⌋−j=1∑⌊can+b⌋[⌊ajc−b+a−1⌋−1]=n⌊can+b⌋−j=0∑⌊can+b⌋−1[⌊a(j+1)c−b−1⌋]
因此我们有a,b<c时
F(a,b,c,n)=n⌊can+b⌋−F(c,−1−b+c,a,⌊can+b⌋−1)
然后就 可以递归了 终止条件a=0
以下代码
1 2 3 4 5 6
| ll exgcd(ll a, ll b, ll c, ll n){ if(a==0) return (n+1)*(b/c); if(a>=c||b>=c) return exgcd(a%c, b%c, c, n) + floor(a/c)*n*(n+1)/2 + floor(b/c)*(n+1); ll temp = (a*n+b)/c; return n*temp - exgcd(c, c-b-1, a, temp-1); }
|