题解 [UVA12775]Gift Dilemma

本文介绍了解决UVA12775问题的方法,通过枚举和扩展欧几里得算法(exgcd),求解特定形式的线性方程组的自然数解。针对方程Ax+By=P-Cz,给出了具体的实现代码。

Luogu link

注意到 C / gcd ⁡ ( A , B , C ) ≥ 200 C/\gcd(A,B,C)\geq200 C/gcd(A,B,C)200,即 C ≥ 200 C\geq 200 C200
于是可以枚举 z z z,即 A x + B y = P − C z Ax+By=P-Cz Ax+By=PCz。因为 C ≥ 200 C\geq200 C200,所以 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=y0kA/gcd(A,B)
此时 k k k 的个数即为答案。因为 x , y ≥ 0 x,y\geq0 x,y0,所以解不等式,得:
⌈ − x 0 d b ⌉ ≤ k ≤ ⌊ y 0 d a ⌋ \lceil\frac{-x_0d}{b}\rceil\leq k\leq\lfloor\frac{y_0d}{a}\rfloor bx0dkay0d

//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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值