A. Vasya and Book
阿新 • • 發佈:2018-12-04
題目原址
http://codeforces.com/contest/1082/problem/A
題目內容
一共n頁書,現在位於第x位,想要看第y頁,每次只能翻d頁,注意總能翻到第1頁和第n頁。
Vasya想知道自己能否在經過無數次翻書後 看到第y頁的內容。
如果可以,請給出最少需要翻幾次書。
題目解析
類似一個模除的問題。
首先思考無法翻到第y頁的情況,即:
①直接翻翻不到
②在到達第1頁和第n頁後也翻不到
對應的式子引出的是:
直接翻不到:
abs(y - x) % d != 0;
第1頁翻不到:
abs(y - 1) % d != 0
第n頁翻不到:
abs(n - y) % d != 0
因此翻不到的情況很好判斷。注:以下簡記 左不通 和 右不通 分別代表第一頁翻不到和第n頁翻不到。
再看最小翻閱次數,這裡可以詳盡的判斷所有情況,也可以統一完成,本人採用的是詳盡的判斷。
將所有可能性列舉出來,即左不通而右通,那麼最短翻閱只有右側的一種方式。
對應的程式碼部分為:
if(abs(y - 1) % d != 0){ //左側不通 //int temp = need(x, y, d); if(abs(n - y) % d != 0){ //右側不通 puts("-1"); continue; } else { count += need(x, n, d); count += need(n, y, d); cout << count << endl; continue; } }
其中,need()函式用來計算從x到y在每次翻閱d的情況下直接到達需要的翻閱次數,如下:
int need(int x, int y, int d){ //3 - 6 3 if(abs(y - x) % d == 0){ return abs(y - x) / d; } else { return abs(y - x) / d + 1; } }
當右側不通,而左側通的時候,情況類似上述:
else if(abs(n - y) % d != 0){ //右側不通 //int temp = need(x, y, d); count += need(x, 1, d); count += need(1, y, d); cout << count << endl; continue; }
而當左右都可通過的時候,只需計算左右兩種方式中翻閱數的最小者即可。
else{ int left = need(x, 1, d) + need(1, y, d); int right = need(x, n, d) + need(n, y, d); count = min(left, right); cout << count << endl; continue; }
題目也可以將不通返回正無窮,從而在返回最小值的過程中失效,減少判斷。
題目總結
很簡單的題目,沒有考察到演算法知識,只是考驗程式設計者對於多種判斷情況的處理。做題時應先想好思路再完成。