網教22.新•真感情醉酒

題目描述

        前兩天,14級計算機巨神真感情學長的一道題被×了!!!被×了!!!被×了!!!

        真感情學長灰常的不開心,所以就去找我喝酒,他帶了一桶S ml的82年啦飛和兩個容量分別爲N ml和M ml的杯子,因爲他要不醉不歸所以帶了非常大的兩個杯子使得兩人一人一杯就可以喝完這一桶酒,也就是說N+M=S,但是陪他喝酒的我不想藉此機會暴露出兩人酒量高低,所以給他提了一個要求——我們兩個人喝的酒必須一樣多,這就讓真感情很尷尬了,所以他請來他的學弟學妹,也就是你們,幫他解決這個問題,如果誰能解決他就罩着你,以後你就可以在計算機學院橫着走了,當然本人爲了考驗真感情的水平,要求他用最少的操作把這桶酒分成兩半(每次操作就是從一個容器向另一個容器倒酒,容器沒有刻度),快努力幫助你們的大神學長吧!

輸入

多組用例,每組用例佔一行包括三個正整數S,N,M分別表示一個桶和兩個杯子的容量(N,M<2^31,S=N+M)

以EOF結束輸入

輸出

對於每組用例,輸出一個整數爲將該桶酒平分的最少操作數,如果無法平分,那麼就輸出“ZGQ drinks off !”

樣例輸入

2 1 1

樣例輸出

1

  測試輸入關於“測試輸入”的幫助 期待的輸出關於“期待的輸出”的幫助 時間限制關於“時間限制”的幫助 內存限制關於“內存限制”的幫助 額外進程關於“{$a} 個額外進程”的幫助
測試用例 1 以文本方式顯示
  1. 2 1 1↵
以文本方式顯示
  1. 1↵
2秒 64M 0
測試用例 2 以文本方式顯示
  1. 5 3 2↵
以文本方式顯示
  1. ZGQ drinks off !↵
2秒 64M 0

題解:
題目改編HDU1495,本是一道簡單的BFS題目。強神改編了一下,把數據範圍從100改到了2^31,然後就不能BFS了……
正好我做這題的時候煮夫坐我旁邊,而且他還是秒A,然後我就順勢膜了一發煮夫。
這道題的方法是用數論解二元一次方程,解出一組通解然後再找最小。方法在強神博客上,我無法給出強神一樣的證明和計算,也只能複製一下了。
一開始看到了一個類似的數論題:
然後我就知道了本題的解題方法是通過列方程,使得ax+by=c,那麼x和y分別代表什麼呢?它們都是代表倒入的次數-倒出的次數,即淨倒入量,這樣ax+by=c的公式也就不難理解了。
強神以前的數論ppt上說過(鏈接裏面也是用的這個方法),解這種題的思路就是先找gcd(最大公約數),如果c%gcd!=0,則方程無解(輸出ZGQ drinks off !);若c%gcd==0,則讓a,b,c同時除gcd(以保證在後面找到的是最小),再繼續往下算。
理論上(ppt上)通過擴展歐幾里得算法可以求出(x,y)的通解,但是限於只能用C語言(而且也沒有必要用),所以只能找其他的方法來確定通解。
由於c=(a+b)/2,所以ax+by=(a+b)/2,
(截自強神博客)


得到通解之後,就是該求答案了。易知肯定一個大於0一個小於0,所以不妨設x>0,y<0,當操作次數最小的時候就是倒入第一個x次,倒入第二個|y|次,但是由於瓶子容積有限,所以倒進倒出操作都是通過大瓶子來解決的,一次倒進操作後爲了繼續使用小瓶子還要將小瓶子中可樂倒回大瓶子中,倒出操作同理,所以總操作次數是2*(x+y)次,但是要注意最後的(a+b)/2是要放回大瓶子裏而不是再倒回,所以乘2之後再減1,所以答案就是2*(|x|+|y|)-1,那麼|x|+|y|該怎麼求呢?

(截自強神博客)



即答案就是a+b-1.

ps:數據要用long long

AC代碼:

#include<stdio.h>  
#include<math.h>  
long long gcd(long long a, long long b)//求最大公約數   
{  
    long long int c;  
    while (b != 0)  /* 餘數不爲0,繼續相除,直到餘數爲0 */  
    {  
        c = a%b;  
        a = b;  
        b = c;  
    }  
    return a;  
}  
  
int main()  
{  
    long long int s, n, m;  
    while (scanf("%lld%lld%lld", &s, &n, &m) != EOF)  
    {  
        long long int a = n, b = m, c = s / 2;//求ax+by=(a+b)/2  
        long long int g = gcd(a, b);  
        if (c%g != 0 || s % 2 == 1)  
            printf("ZGQ drinks off !\n");  
        else  
        {  
            a = a / g;  
            b = b / g;  
            c = c / g;  
            long long int x = (1 - b) / 2, y = (1 + a) / 2;//此處x和y是兩特解,通解爲x+k*b,y-k*a  
            x = x < 0 ? -x : x;  
            y = y < 0 ? -y : y;  
            long long int ans = (x+y) * 2;  
            printf("%lld\n", ans-1);  
        }  
    }  
    return 0;  
}  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章