类欧几里得算法学习笔记

解决的问题

形如\(f(a,b,c,n)=\sum \limits_{i=0}^n\lfloor \frac{ai+b}{c}\rfloor\)的式子的快速求解

推导

分成2种情况进行讨论:

a >= c或b >= c

从小学的y余数开始,\(a \div b = p ...... q\)
我们变换一下,\(a=bp+q\),其中\(p = \lfloor \frac{a}{b}\rfloor, q = a\ mod\ b\)
那么,我们现在开始对\(\sum \limits_{i=0}^n\lfloor \frac{ai+b}{c}\rfloor\)进行变换

\[原式 = \sum \limits_{i=0}^n\lfloor \frac{\lfloor\frac{a}{c}\rfloor ci+\lfloor\frac{b}{c}\rfloor c + (a\ mod\ c)i+(b\ mod\ c)}{c}\rfloor \]

\[=\sum \limits_{i=0}^n \lfloor \lfloor\frac{a}{c} \rfloor i+ \frac{b}{c} + \lfloor \frac{(a\ mod\ c)i + (b\ mod\ c)}{c} \rfloor\rfloor \]

显然,\(\lfloor \frac{a}{c}\rfloor i\)\(\lfloor \frac{b}{c}\rfloor\)肯定是一个整数,所以我们可以把这个东西提到外面去

\[=\sum \limits_{i=0}^{n}\lfloor \frac{a}{c}\rfloor i + \sum \limits_{i = 0}^{n} \lfloor \frac{b}{c}\rfloor + \sum \limits_{i = 0}^{n}\lfloor \frac{(a\ mod\ c)i + (b\ mod\ c)}{c} \rfloor \]

\[= \frac{n(n + 1)\lfloor \frac{a}{c}\rfloor}{2} + (n + 1)\lfloor \frac{b}{c} \rfloor + \sum \limits_{i = 0}^{n}\lfloor \frac{(a\ mod\ c)i + (b\ mod\ c)}{c} \rfloor \]

观察一下最后一项,不就是\(f(a\ mod\ c,b\ mod\ c, c, n)\)吗?
所以我们现在把所有的\(a \geq c或 b \geq c\)的情况转化成了\(a<c且b<c\)的情况了

a < c且b < c

此处的推导精髓之处和推数论函数的部分很相似,不过不需要数论函数的基础。

\[\sum \limits_{i=0}^{n} \lfloor \frac{ai+b}{c}\rfloor = \sum \limits_{i=0}^{n}\sum \limits_{j=0}^{\lfloor \frac{ai+b}{c}\rfloor-1}1 \]

我们发现了\(j\)\(i\)是有关的,试图将\(j\)变成和\(i\)无关的式子

\[原式=\sum \limits_{j=0}^{\lfloor \frac{an+b}{c}\rfloor-1}\sum \limits_{i=0}^{n}[j < \lfloor\frac{ai+b}{c} \rfloor] \]

我们将\([j< \lfloor \frac{ai+b}{c}\rfloor]\)进行变换,此处运用一下放缩的寄巧

\[j<\lfloor \frac{ai+b}{c}\rfloor \iff j+1\leq \lfloor \frac{ai+b}{c}\rfloor\iff j+1\leq \frac{ai+b}{c} \]

然后移项,

\[j+1\leq \frac{ai + b}{c} \]

\[\Rightarrow jc + c \leq ai + b \]

\[\Rightarrow ai \geq jc + c - b \]

\[\Rightarrow i \geq \frac{jc + c - b}{a} \]

缩放回来

\[i >\lfloor \frac{jc + c - b}{a}\rfloor \]

把这个东西带回原式

\[\sum \limits_{j=0}^{\lfloor\frac{an+b}{c} \rfloor-1}\sum \limits_{i=0}^{n}[i > \lfloor\frac{jc + c - b}{a}\rfloor] \]

\[=\sum \limits_{j=0}^{\lfloor \frac{an+b}{c} \rfloor-1}n-\lfloor \frac{jc + c - b}{a}\rfloor \]

\[=n\lfloor \frac{an+b}{c}\rfloor - \sum \limits_{i=0}^{\lfloor \frac{an+b}{c}\rfloor-1}\lfloor\frac{ic + c - b - 1}{a} \rfloor \]

\[= n\lfloor \frac{an + b}{c}\rfloor - f(c, c - b - 1, a, \lfloor \frac{an + b}{c} \rfloor - 1) \]

例题 P5171Earthquake

题目

\(ax+by\leq c\)的非负解数,其中给定\(a,b,c\leq 10^9\)

解法

观察到\(ax+by\leq c\)可以转化成\(y \leq \lfloor \frac{c-ax}{b}\rfloor\)的形式
对于\(y\)则会有\(\lfloor \frac{c-ax}{b}\rfloor+1\)个数是合法的
假如\(y=0\),可以求得x的取值范围\(ax\leq c\),形似类欧几里得(上面讲的),移项得\(x \leq \lfloor \frac{c}{a}\rfloor\),所以对于所有的\(x\)的合法数目的累计和为

\[\sum \limits_{i=0}^{\lfloor \frac{c}{a}\rfloor}\lfloor\frac{c-ax}{b}\rfloor+1 \]

然后发现这个东西很想类欧,但是呢要稍微使用一点变换,让\(x\)前面的系数是\(>0\)
因此我们考虑加上\(b\),让这个式子变为:

\[\sum \limits_{i=0}^{\lfloor \frac{c}{a}\rfloor}\lfloor \frac{(b-a)x+c}{b} \rfloor-x+1 \]

不过因此要求\(b>a\),对此的处理就是

  if (b < a) 
    swap (b, a);

对前面的式子进行处理,就是\(f(b-a,c, b, \frac{a}{c})\)
后面的用一下等差数列求和
贴代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll a, b, c, s;
inline ll f(ll a, ll b, ll c, ll n) { // 类欧
  if (a == 0)
    return ((b / c) * (n + 1));
  if (a >= c || b >= c)
    return f(a % c, b % c, c, n) + (a / c) * n * (n + 1) / 2 + (b / c) * (n + 1);
  ll m = (a * n + b) / c;
  return n * m - f(c, c - b - 1, a, m - 1);
}
signed main() {
  cin >> a >> b >> c;
  if (b < a)
    swap(b, a);
  cout << f(b - a, c, b, c / a) - (c / a) * (c / a + 1) / 2 + (c / a) + 1 << endl;
  return 0;
}
posted @ 2023-03-13 22:22  georegyucjr  阅读(23)  评论(0)    收藏  举报