1. 程式人生 > 實用技巧 >BZOJ-2987 Earthquake(類歐幾里得演算法)

BZOJ-2987 Earthquake(類歐幾里得演算法)

題目描述

  給定 \(A,B,C\),求滿足方程 \(Ax+By\leq C\)非負 整數解 \((x,y)\)\(A,B\leq 10^9,C\leq \min(A,B)\times 10^9\))。

分析

  考慮列舉 \(y\),移項得:\(0\leq y\leq \lfloor\frac{C-Ax}{B}\rfloor\),當 $ x=0$ 時,\(y\) 列舉的上界為 \(\lfloor\frac{C}{A}\rfloor\)

  這相當於求線段 \(y=\frac{C-Ax}{B}(0\leq y\leq \lfloor\frac{C}{A}\rfloor)\) 在第一象限和 \(x,y\)

正半軸內整點的數量。

  把斜率為負調整成斜率為正的線段,原來線段的兩端點為 \((0,\frac{C}{B}),(\lfloor\frac{C}{A}\rfloor,\frac{C-A\lfloor\frac{C}{A}\rfloor}{B})\),將兩端點對換,分別為 \((0,\frac{C-A\lfloor\frac{C}{A}\rfloor}{B}),(\lfloor\frac{C}{A}\rfloor,\frac{C}{B})\),此時線段為 \(y=\frac{A}{B}x+\frac{C-A\lfloor\frac{C}{A}\rfloor}{B}=\frac{Ax+C\% A}{B}\)

  問題即求(加 \(1\) 是因為 \(x=0\) 時也是合法解):

\[\sum_{i=0}^{\lfloor\frac{C}{A}\rfloor}\Big(\Big\lfloor\frac{Ax+C\%A}{B}\Big\rfloor+1\Big)=\sum_{x=0}^{\lfloor\frac{C}{A}\rfloor}\Big(\Big\lfloor\frac{Ax+C\%A+B}{B}\Big\rfloor\Big) \]

  考慮一個一般性問題:

\[f(a,b,c,n)=\sum_{i=0}^{n}\Big\lfloor\frac{ai+b}{c}\Big\rfloor \]

  \(1.\)

\(a\geq c\) \(b\geq c\) 時,

  \(2.\)\(a<c\) \(b<c\) 時,

  可以發現右邊遞迴成為子問題,繼續一輪操作即可。邊界條件:\(a=0\)

程式碼

#include<bits/stdc++.h>
using namespace std;
long long A,B,C;
long long solve(long long a,long long b,long long c,long long n)
{
    if(a==0)
        return (n+1)*(b/c);
    if(a>=c||b>=c)
        return solve(a%c,b%c,c,n)+(a/c)*n*(n+1)/2+(b/c)*(n+1);
    long long m=(a*n+b)/c;
    return n*m-solve(c,c-b-1,a,m-1);
}
int main()
{
    cin>>A>>B>>C;
    cout<<solve(A,C%A+B,B,C/A)<<endl;
    return 0;
}