UVA12775 Gift Dilemma(exgcd)

题目传送门

题意: 给定 T ( T < = 100 ) T(T<=100) T(T<=100) A , B , C , P ( A , B , C , P < = 1 e 8 ) A,B,C,P(A,B,C,P<=1e8) A,B,C,P(A,B,C,P<=1e8),问你每组的数组中,有多少种方法使得 A x + B y + C z = P Ax+By+Cz=P Ax+By+Cz=P。保证 C / g c d ( a , b , c ) > = 200 C/gcd(a,b,c)>=200 C/gcd(a,b,c)>=200

思路: 因为至少保证了 C / g c d ( a , b , c ) > = 200 C/gcd(a,b,c)>=200 C/gcd(a,b,c)>=200,我们可以枚举 z z z,使得 A x + B y = P − C z Ax+By=P-Cz Ax+By=PCz

  1. D = P − C z D=P-Cz D=PCz
  2. A x + B y = D Ax+By=D Ax+By=D
  3. 求出一组特解: x , y x,y x,y
  4. 显然, A ( x − k ∗ B g c d ( A , B ) ) + B ( y + k ∗ A g c d ( A , B ) ) = D A(x-k*\frac{B}{gcd(A,B)})+B(y+k*\frac{A}{gcd(A,B)})=D A(xkgcd(A,B)B)+B(y+kgcd(A,B)A)=D
  5. x − k ∗ B g c d ( A , B ) > = 0 , y + k ∗ A g c d ( A , B ) > = 0 x-k*\frac{B}{gcd(A,B)}>=0,y+k*\frac{A}{gcd(A,B)}>=0 xkgcd(A,B)B>=0,y+kgcd(A,B)A>=0
  6. ⌈ − y ∗ g c d ( A , B ) A ⌉ < = k < = ⌊ x ∗ g c d ( A , B ) B ⌋ \lceil-y*\frac{gcd(A,B)}{A}\rceil<=k<=\lfloor x*\frac{gcd(A,B)}{B}\rfloor yAgcd(A,B)<=k<=xBgcd(A,B)

所以我们只需要提前算出 A x + B y = g c d ( A , B ) Ax+By=gcd(A,B) Ax+By=gcd(A,B)的一组特解 x 0 , y 0 x_0,y_0 x0,y0,然后枚举 z z z就行了。时间复杂度为 O ( T ∗ P C ) O(T*\frac{P}{C}) O(TCP)

代码:

#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
    int x=0,f=1;
    char ch=gc();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=gc();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=gc();
    }
    return x*f;
}
using namespace std;
// Author : ACfunhsl
// time : 2021/4/1 15:16:18
#define int long long
const int N=1e5+50;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;

int exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1;
		y=0;
		return a;
	}
	int res = exgcd(b,a%b,x,y);
	int t = x;
	x = y;
	y = t - (a/b) * y;
	return res;
}
signed main()
{
	int t;
	cin>>t;
	int cas = 1;
	while(t--)
	{
		int a,b,c,p;
		cin>>a>>b>>c>>p;
		int d = __gcd(a,b);
		int res=0;
		int x0,y0;
		exgcd(a,b,x0,y0);
		for(int i=0;i*c<=p;i++)
		{
			int k = p-i*c;
			if(k%d) continue;
			int x =x0 * k/d;
			int y =y0 * k/d;
			res += (floor(1.0*x*d/b)-ceil(-1.0*y*d/a)+1);
		}
		cout<<"Case "<<cas++<<": "<<res<<endl;
	}



	return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值