解决的问题
形如\(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;
}