【瞎讲】类欧几里得入土教程
产生背景
假设我们现在得到一条直线(y=ax+b),现在要数出(x in [0,n])时,在(x)正半轴和这条直线之间的整点个数,(n le 10^{18})
解决思路
这个方程一定可以化为这样的形式
[y=dfrac {ax+b}{c}
]
枚举(x in [0,n]),直接算其整点个数,答案就是
[sum_{i=0}^n lfloor dfrac {ai+b}{c}
floor
]
考虑如何快速计算这个式子,我们考虑如何化为子问题
前置芝士
向下取整有这一个性质(其他性质可以由此推出):
[lfloor dfrac {a+c} b
floor=lfloor dfrac {a\%b+lfloordfrac a b
floor b+c}{b}
floor=lfloor dfrac {a\%b+c}{b}
floor + lfloordfrac a b
floor
]
然后有两个重要而显然的性质:
[lfloor {aover b}
floor le {aover b}
]
类似的
[lceil {aover b}
ceil ge {aover b}
]
还有相互转换法则
[lfloor {aover b}
floor =lceil {a-b+1over b}
ceil
]
类似的
[lceil {aover b}
ceil = lfloor{a+b-1 over b}
floor
]
我觉得不用解释了吧...
解决问题
有了上面的芝士,我们考虑
[sum_{i=0}^n lfloor dfrac {ai+b}{c}
floor
]
时,稍微化归一下:
-
(age c)时
[][] -
(bge c)时
同样的
[][ ]
现在就只要计算(a,b< c)的情况即可,进行一波和式变换
[sum_{i=0}^n lfloor {ai+b over c}
floor
]
创造条件
[=sum_{i=0}^n sum_{j=1}^{lfloor {ai+b over c}
floor} 1
]
和式套路
[= sum_{i=0}^nsum_{j=1}^{lfloor {an+b over c}
floor} [j le lfloor {ai+b over c}
floor]=sum_{j=1}^{lfloor {an+b over c}
floor} sum_{i=0}^n [j le lfloor {ai+b over c}
floor]
]
根据前置芝士
[=sum_{j=1}^{lfloor {an+b over c}
floor} sum_{i=0}^n [cj le {ai+b} ]
]
考虑(i)
[=sum_{j=1}^{lfloor {an+b over c}
floor} sum_{i=0}^n [cj-b le ai ]
]
根据前置芝士
[=sum_{j=1}^{lfloor {an+b over c}
floor} sum_{i=0}^n [lceil{cj-bover a}
ceil le i ]
]
此时可以直接算出来第二个(Sigma)的值
[=sum_{j=1}^{lfloor {an+b over c}
floor} (n-lceil{cj-bover a}
ceil+1)
]
根据前置芝士
[=sum_{j=1}^{lfloor {an+b over c}
floor} (n-lfloor{cj-b+a-1over a}
floor+1)
]
提出来
[=(n+1)lfloor {an+b over c}
floor -sum_{j=1}^{lfloor {an+b over c}
floor} lfloor{cj-b+a-1over a}
floor
]
后面就是一个子问题啊!问题规模降了一半以上(当(c=1)的时候可以直接等差数列求和(O(1))算)
所以解决原问题的复杂度为
[T(n)le O(1)+T({n over 2})
]
根据主定理
[T(n)le log_2 n
]
那么问题来了,为啥叫做类欧几里得算法呢?因为复杂度证明是相似的...滑稽