扩欧——NKOJ P3677 观光车

问题描述

何老板带领n名游客来到一景区大门口,需要乘坐观光车游览景区。
景区提供两种观光车,一种是每辆车可以坐a名游客,包一辆车费用是p1块钱;另一种每辆车可以坐b名游客,包一辆车费用是p2块钱。
何老板想让这n名游客都坐上观光车,且每辆车都坐满。问何老板至少要花费多少钱?

输入格式
第一行,一个整数n,表示游客的总数。
第二行,两个空格间隔的整数,表示p1和a
第三行,两个空格间隔的整数,表示p2和b

输出格式
一行,一个整数,表示所需最少费用。
如果无解,输出“-1”

样例输入 1

43
1 3
2 4

样例输出 1
15

样例输入 2
40
5 9
5 12

样例输出 2
-1

提示
样例1说明:第一种车13辆,第二种车1辆
1 <= n,a,b,p1,p2 <= 2,000,000,000

分析:
设第一种车、第二种车分别包x,y,辆
x*a+y*b=n;   
设 x1,y1 是满足上式的一组解
cost= (x1+t*dx)*p1+(y1-t*dy)*p2
    =x1*p1+y1*p2+ (dx*p1-dy*p2)*t;
是一个关于t的一次函数;记斜率为K=dx*p1-dy*p2
由于x,y>0,可以求出t的定义域:
	x=x1+dx*t>=0  ==> t >= -x1/dx;
	y=y1-dy*t>=0  ==> t <= y1/dy;
若  K<0 ,t=tmin=-x1/dx;
    K>=0,t=tmax=y1/dy;
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>

#define LL long long
using namespace std;
LL n,p1,p2,a,b;

LL extend_gcd(LL a,LL b,LL &x,LL &y ){
	LL x0,y0,r;
	if(b==0){x=1;y=0; return a;}
	r=extend_gcd(b,a%b,x0,y0);
	x=y0;  y=x0-a/b*y0;
	return r;
}

int main(){
	LL gcd,x,y,mint,maxt,ans,dx,dy,k,t;
	cin>>n>>p1>>a>>p2>>b;
	gcd=extend_gcd(a,b,x,y);
	if(n%gcd!=0){
		cout<<-1; return 0;
	}
	x= x*n/gcd; y=y*n/gcd;
	ans= x*p1+y*p2;
	dx= b/gcd;	dy= a/gcd;
	k= (dx*p1-dy*p2);
	maxt= floor(((double) y)/dy);
	mint= ceil(((double) x)/ -dx);
	if(maxt<mint){
		cout<<"-1"; return 0;
	}
	else if(k>0) t=mint;
	else t=maxt;
	cout<<ans+k*t<<endl;
	//cout<<"k= "<<k<<" dx= "<<dx<<" dy="<<dy<<endl; 
	//cout<<"x= "<<x<<" y= "<<y<<" mint= "<<mint<<" maxt= "<<maxt<<endl;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值