题目链接:
传送门
#include<cstdio>
using namespace std;
int gcd(int a,int b) {
return !b ? a : gcd(b,a%b);
}
int main() {
int s, n, m;
while(scanf("%d%d%d",&s,&n,&m)) {
if(s == 0 && n== 0 && m== 0) break;
s/=gcd(n,m);
if(s % 2 != 0)printf("NO\n");
else printf("%d\n",s-1);
}
return 0;
}
这道是首先第一反应可以用bfs做,bfs的具体方法就是枚举abc间倒来倒去的操作总共六个,然后记录状态与前面pots(如果你是刷kaungbin提单刷到这道题)的操作相似。但这里我想讲的是一种数论的做法
数论涉及到的知识点是exgcd相关题目
具体思路大致如下:
首先我们设两个小瓶子容积分别为a,b,问题转化成通过两个小瓶子的若干次倒进或倒出操作得到(a+b)/2体积的可乐,设两个小瓶子被操作x次和操作x次;那么此时问题就转换为求ax+by=(a+b)/2的不定方程,不定方程的具体求法可以参考上方那个链接。首先通过exgcd求出x和y的一个特解,然后通过特解求出通解。在通解中我们要选择一个x+y尽可能小的解。此时我们可以通过特解推出这个解为(c+d)/2.通过x和y的通解形式显然可以看出x和y一正一负,不妨设x<0,那么就是往第一个小瓶子倒进x次,第二个小瓶子倒出y次,但是由于瓶子容积有限,所以倒进倒出操作都是通过大瓶子来解决的,一次倒进操作后为了继续使用小瓶子还要将小瓶子中可乐倒回大瓶子中,倒出操作同理,所以总操作次数是(c+d)/2*2=c+d,但是注意最后剩下的(a+b)/2体积的可乐一定是放在两个小瓶子中较大的那个中,而不是再倒回到大瓶子中,所以操作数要减一。
详细的推导过程请看某数学大佬的博客
这篇博客探讨了一种使用数论方法解决关于通过两个不同容量小瓶子倒水,最终达到目标体积的策略。核心是应用扩展欧几里得算法(exgcd)找到不定方程的解,通过特解和通解找到最小操作次数。关键在于理解如何从特解推导出实际操作次数,并注意到最终可乐会存储在较大瓶子中,因此需要减去一次操作。这种方法避免了传统枚举操作的复杂性。
1248

被折叠的 条评论
为什么被折叠?



