注意到
C
/
gcd
(
A
,
B
,
C
)
≥
200
C/\gcd(A,B,C)\geq200
C/gcd(A,B,C)≥200,即
C
≥
200
C\geq 200
C≥200。
于是可以枚举
z
z
z,即
A
x
+
B
y
=
P
−
C
z
Ax+By=P-Cz
Ax+By=P−Cz。因为
C
≥
200
C\geq200
C≥200,所以
z
z
z 最多枚举
5
×
1
0
5
5\times10^5
5×105 次,复杂度足够。
接下来问题转化为
A
x
+
B
y
=
K
Ax+By=K
Ax+By=K 的自然数解。使用
exgcd
\text{exgcd}
exgcd 接触该方程一组特解
x
0
,
y
0
x_0,y_0
x0,y0,通解即为:
{
x
=
x
0
+
k
B
/
gcd
(
A
,
B
)
y
=
y
0
−
k
A
/
gcd
(
A
,
B
)
\begin{cases}x=x_0+kB/\gcd(A,B)\\y=y_0-kA/\gcd(A,B)\end{cases}
{x=x0+kB/gcd(A,B)y=y0−kA/gcd(A,B)
此时
k
k
k 的个数即为答案。因为
x
,
y
≥
0
x,y\geq0
x,y≥0,所以解不等式,得:
⌈
−
x
0
d
b
⌉
≤
k
≤
⌊
y
0
d
a
⌋
\lceil\frac{-x_0d}{b}\rceil\leq k\leq\lfloor\frac{y_0d}{a}\rfloor
⌈b−x0d⌉≤k≤⌊ay0d⌋
//UVA12775
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll gcd(ll a, ll b){ return b ? gcd(b,a%b) : a; }
void exgcd(ll a, ll b, ll &x, ll &y){
if(b == 0){ x = 1, y = 0; return; }
exgcd(b, a%b, x, y);
int z = y; y = x - (a / b) * y; x = z;
}
int main(){
// freopen("_.txt", "w", stdout);
int asdf; scanf("%d", &asdf);
for(int ghjk = 1; ghjk <= asdf; ++ ghjk){
ll a, b, c, p; scanf("%lld%lld%lld%lld", &a, &b, &c, &p);
ll x = 0, y = 0, d = gcd(a,b), ans = 0; exgcd(a, b, x, y);
for(ll z = 0; c * z <= p; ++ z){
ll k = p - c * z, xx = x * k / d, yy = y * k / d;
if(k%d) continue;
ll l = ceil(-1.0*xx*d/b), r = floor(1.0*yy*d/a);
// printf("%lld %lld %lld %lld %lld %lld %lld %lld\n", a, xx, b, yy, d, k, l, r);
ans += r - l + 1;
}
printf("Case %d: %lld\n", ghjk, ans);
}
return 0;
}
本文介绍了解决UVA12775问题的方法,通过枚举和扩展欧几里得算法(exgcd),求解特定形式的线性方程组的自然数解。针对方程Ax+By=P-Cz,给出了具体的实现代码。
2198

被折叠的 条评论
为什么被折叠?



