ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hdu1495 非常可乐

2021-02-08 22:01:10  阅读:247  来源: 互联网

标签:非常 seeyou gcd int hdu1495 abs 平分 可乐


非常可乐

hdu1495

题目

Description

大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。

Input

三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。

Output

如果能平分的话请输出最少要倒的次数,否则输出"NO"。

Sample Input

7 4 3
4 1 3
0 0 0

Sample Output

NO
3

解题思路

  1. 首先总可乐升数是奇数肯定不能被平分
  2. x =b杯子倒进来次数-倒出去的次数,y同理, __为什么是-不是+,因为倒出去后杯子可乐减少,统计的是最后杯子剩余的可乐,所以做的是代数上的加减
  3. 既然要平分,那么经过移动后想要满足b ∗ x + c ∗ y = a / 2 bx+cy=a/2bx+cy=a/2,已知扩展欧几里得b ∗ x + c ∗ y = g c d ( b , c ) bx+cy=gcd(b,c)bx+cy=gcd(b,c),如果满足gcd(b,c) == a/2,那么就能平分.
  4. 但是扩展欧几里得求出的只是一组特解x,y,不一定是最小操作值,
  5. 通过(x增加,y减少)
    b ∗ ( x − c / g c d ( b , c ) ) + c ∗ ( y + b / g c d ( b , c ) ) b(x-c/gcd(b,c))+c(y+b/gcd(b,c))b∗(xc/gcd(b,c))+c∗(y+b/gcd(b,c))
    __(x减少,y增加)
    b ∗ ( x + c / g c d ( b , c ) ) + c ∗ ( y − b / g c d ( b , c ) ) b(x+c/gcd(b,c))+c(y-b/gcd(b,c))b∗(x+c/gcd(b,c))+c∗(yb/gcd(b,c))
    找到最小的x,y
  6. 因为每一次倒入小瓶子b,c中,如果要继续使用小瓶子,那么必须倒回到大瓶子里去,但是最后一次不需要,所以ans = 2*(abs(x)+abs(y)) - 1

代码

#include <iostream>
#include <string.h>
#include <math.h>

using namespace std;

int a,b,c;

int exgcd(int a,int b,int& x,int& y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int res = exgcd(b,a%b,x,y);
	int temp = y;
	y = x - (a/b)*y;
	x = temp;
	return res;
}
int main() {
//	freopen("a.txt","r",stdin);
	while (scanf("%d%d%d",&a,&b,&c) && a) {
		int x , y;
		if (a % 2) { // 奇数一定不能被平分 
			printf("NO\n");
			continue;
		}
//		if (b < c) swap(b,c); 扩展ojld中 a,b互换,其实x,y也互换了 
		int gcd = exgcd(b,c,x,y);
		if ( (a/2) % gcd != 0) { // 不满足 ax+by == gcd(),偶数升可乐不能通过移动操作使得其被平分 
			printf("NO\n");
			continue;
		}
		int k = a / 2 / gcd;
		// 扩展欧几里得的性质 ,m = n * gcd(); 
		x = k * x;
		y = k * y;
		// ****x,y只是通过欧几里得求出来的一组特解而已,但不一定是使得操作满足最小值****
		while (1) { // 找到操作次数最少的 x+y 
			// 通过增大x,减小y,相互+-(A/bcd)抵消了 
			if (abs(x -(c / gcd)) + abs(y + (b / gcd)) < abs(x) + abs(y) ) {
				x -= c/gcd;
				y += b/gcd;
			}
			// 减小x,增大y, 
			else if (abs(x +(c / gcd)) + abs(y - (b / gcd)) < abs(x) + abs(y)) {
				x += c/gcd;
				y -= b/gcd;
			}
			else  break;
		}
		// 看分析 
		cout << (abs(x) + abs(y))*2 -1 << endl;
	}
	return 0;
}

标签:非常,seeyou,gcd,int,hdu1495,abs,平分,可乐
来源: https://www.cnblogs.com/Jernewson/p/14391226.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有