1018 - 数论之扩展欧几里得 - 吃蛋糕

吃蛋糕

描述

Beny 想要用蛋糕填饱肚子。Beny 一共想吃体积为 c 的蛋糕,他发现有两种蛋糕可以吃,一 种体积为 a,一种体积为 b,但两种蛋糕各有特色。Beny 想知道他一共有多少种不同吃法, 使得他恰好可以填饱肚子。

输入

第一行一个 t

接下来 t 行,每行三个正整数 a,b,

输出

对于每个 a,b,c,输出一个整数表示有几种不同吃法

样例输入 1
3
2 3 4
3 4 24
3 7 11
样例输入 2
4
12 13 1003
56 44 792
4616 5364 836482148
3836501 7035978 77151863500136

样例输出 1
1
3
0
样例输出 2
6
2
135
3

提示

对于 30%的数据 t<=10,a,b,c<=100

对于 60%的数据 t<=100,a,b,c<=10^9

对于 100%的数据 t<=10000,a,b,c<=10^14

 

题意:

求 a*x+b*y=c 有多少组非负整数解

 

分析

这个式子很扩欧

令gd = gcd (a,b)

若c%gd!=0(也就是说 c 不能整除gcd(a,b))那么方程肯定不存在一组合法整数解(强势记忆:所有数论的题都是在整数范围下求解的,dzy吐槽你看整个过程中哪里出现过小数),这个证明很显然,令 a=k1*g,b=k2*g,则左边的和一定会带一个 g ,那右边也一样

如果有解,我们就将式子左右同时除以一个 gd ,得到 a1*x+b1*y=c1    -- (1)

然后由于这个式子与a1*x+b1*y=1   --(2) 的解是等价的,就相当于现在我们求出

a1*x+b1*y=1这个式子的一组合法解,然后乘以 c1 就是(1)的一组合法解了

由于题目要求的是非负整数解,我们将得到的一组特解调整一下 x=(x%b1+b1)%b1得到正数

又因为最后要求合法的解的个数,我们就求出 x 的下界,对应着 y 的上界,然后看 y 能调整多少次(也就是能除多少个 a1)

得到ans,最后还要+1,因为要算上没有调整的,也算一组解对吧?

 

 

会不会有小可爱像我一样纠结,为什么不能从最原始的式子:a*x+b*y=c

直接算 a*x+b*y=1 这个式子的解然后再乘以 c 还原最开始的解呢?

dalao请指教

 

 

代码

(数据有问题,咱懂思想即可)



#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a,b,c;
int t;
ll gcd(ll x,ll y){
	ll z=x%y;
	while(z){x=y;y=z;z=x%y;}
	return y;
}
void exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1;y=0;return;
	}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
}
ll mul(ll a,ll b,ll p){
	ll res=0;
	while(b){
		if(b&1) res=(res+a)%p;
		a=(a+a)%p;
		b>>=1;
	}
	return res;
}
int main(){
	scanf("%d",&t);
	while(t--){
		ll ans=0;
		scanf("%lld%lld%lld",&a,&b,&c);
		ll gd=gcd(a,b);
		if(c%gd) {printf("0\n");continue;}
		a/=gd;b/=gd;c/=gd;
		ll x,y;
		exgcd(a,b,x,y);
		x=mul(x,c%b,b);//得到(1)的最小解
		x=(x%b+b)%b;//最小解可能为负,将其调整为正
		y=(c-a*x)/b;
		if(y<0) {printf("0\n");continue;}
		else printf("%lld\n",y/a+1);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值