【LG5171】Earthquake

【LG5171Earthquake】

题面

洛谷

题解

本题需要用到类欧几里得算法。

前置知识:类欧几里得

就是求函数\[\varphi (a,b,c,n)=\sum_{i=0}^n \left\lfloor\frac {ai+b}c\right\rfloor\]
的值(其实还有两种形式,但是我还不会这里不做介绍)。

它的几何意义是直线\(y=\frac {ax+b}c\)\([0,n]\)下方或过直线的第一象限内的整点数

\(\xi(i)=\lfloor\frac {ai+b}c\rfloor\)

由结论\(\lfloor\frac{Ax}y\rfloor = \lfloor\frac{A(x\;\bmod\;y)}y\rfloor + A\lfloor\frac xy\rfloor\)

可以得到
\[ \xi(i)=\left\lfloor\frac{ai}c+\frac bc\right\rfloor \\=\left\lfloor\frac{(a\bmod c)i+(b\bmod c)} c\right\rfloor+i\Big\lfloor\frac ac\Big\rfloor+\Big\lfloor\frac bc\Big\rfloor \]

然后可以得到\(\varphi(a,b,c,n)=\varphi(a\bmod c,b\bmod c, c, n)+\frac {n(n+1)}2\lfloor\frac ac\rfloor+(n+1)\lfloor\frac bc\rfloor\)

现在我们将\(\xi(i)\)的值限制在了\([0,n]\)之内,考虑将\(\varphi\)用新的式子表示出来:

\[ \varphi(a,b,c,n)=\sum_{i=0}^n\sum_{d=1}^{\lfloor\frac {an+b}c\rfloor}\left[\lfloor\frac {ai+b}c\rfloor\geq d\right]\\ =\sum_{i=0}^n\sum_{d=0}^{\lfloor\frac {an+b}c\rfloor-1}\left[a^{-1}c\lfloor\frac {ai+b}c\rfloor\geq a^{-1}c(d+1)>a^{-1}(cd+c-1)\right]\\ =\sum_{i=0}^n\sum_{d=0}^{\lfloor\frac {an+b}c\rfloor-1}\left[i>\frac {cd+c-b-1}{a}\right] \]

而右边艾弗森括号里的相当于统计有多少个数大于\(\frac {cd+c-b-1}{a}\),就相当于\(n-\lfloor\frac {cd+c-b-1}{a}\rfloor\),那么
\[ \varphi(a,b,c,n)=\sum_{d=0}^{\lfloor\frac {an+b}c\rfloor-1}(n-\left\lfloor\frac {cd+c-b-1}{a}\right\rfloor)\\ =n\left\lfloor\frac {an+b}c\right\rfloor-\sum_{d=0}^{\lfloor\frac {an+b}c\rfloor-1}\left\lfloor\frac {cd+c-b-1}{a}\right\rfloor\\ =n\left\lfloor\frac {an+b}c\right\rfloor-\varphi(c,c-b-1,a,\left\lfloor\frac {an+b}c\right\rfloor-1)\\ =n\left\lfloor\frac {an+b}c\right\rfloor-\varphi(c,c-b-1,a,\xi(n)-1) \]
现在就可以递归处理了,至于复杂度,仔细思考一下发现和\(\gcd\)复杂度一样,为\(O(\log n)\)

代码实现:

long long f(long long a, long long b, long long c, long long n) { 
    if (!a) return b / c * (n + 1); 
    else if (a >= c || b >= c) return f(a % c, b % c, c, n) + n * (n + 1) / 2 * (a / c) + (n + 1) * (b / c); 
    else {
        long long m = (a * n + b) / c; 
        return n * m - f(c, c - b - 1, a, m - 1); 
    } 
} 

关于此题

\[ax+by-c\leq 0\]

就是求\(y=\frac {c-ax}{b}\)下方或过直线在第一象限及正半轴上的整点数。

\(n=\lfloor\frac ca\rfloor\),那么两端的点就为\((0,\frac cb),(n,\frac {c-an}b)\)

显然可以把两端的\(y\)值调换一下,那么两点变为\((0,\frac {c-an}b),(n,\frac cb)\)

此时这条直线变为\(y=\frac ab x+\frac {c-an}{b}=\frac {ax+(c\;\bmod\;a)}b\),然后套到类欧的模板里在加上坐标轴上的即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
long long a, b, c; 
long long f(long long a, long long b, long long c, long long n) { 
    if (!a) return b / c * (n + 1); 
    else if (a >= c || b >= c) return f(a % c, b % c, c, n) + n * (n + 1) / 2 * (a / c) + (n + 1) * (b / c); 
    else {
        long long m = (a * n + b) / c; 
        return n * m - f(c, c - b - 1, a, m - 1); 
    } 
} 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    cin >> a >> b >> c; 
    printf("%lld\n", f(a, c % a, b, c / a) + c / a + 1); 
    return 0; 
} 

猜你喜欢

转载自www.cnblogs.com/heyujun/p/11804358.html