Codeforces Round #501 (Div. 3) D Walking Between Houses
翻譯
給你一條數軸(出題人很喜歡數軸啊),上面有排列著\(n\)個點,編號為\(1\)到\(n\)(你開始在\(1\))。每次你要從一個點移動到另一個點(可以重復)。移動距離為兩點坐標之差的絕對值,問你是否能否在\(k\)次機會內裏一共移動\(s\)距離,並輸出方案。
思路
第四題還是比較難的,賽後想了幾分鐘時才有頭緒。
毫無疑問還是貪心(出題人很喜歡貪心啊)!那麽我們分類討論,先看不合法的情況
無論如何走你也走不到那個距離
無論如何走你也會走超那個距離
看來只要能走到那個距離除外都是不合法的,因此就一個走超和走不到(我沒廢話!)。
那麽如何解決?很簡單,走不到就是每次你從最左邊走到最右邊,再從最右邊走到最左邊,這樣循環下去,一直到你走完了還不到。
走超了就是你每次走一個距離,進行\(k\)次後還是大於\(s\)。
那麽這兩個代碼好寫極了,不用我教你吧\(^_^\)。
到了合法的情況,受到不合法的啟發,我們可以想到這樣的方法:每一次啊,先從最左邊走到最右邊,再從最右邊走到最左邊,循環下去,一直到你剩下的距離不足\(n-1\)(\(n-1\)就是數軸兩個端點間的距離)的時候啊,直接走完即可(由於在此期間你只會位於數軸的兩個端點)。
但是不會那麽簡單的\(QAQ\),直接走完可不行啊,如果要走\(32\)那麽遠,\(4\)下子走完,數軸有\(11\)個點。照我們說的,當還有兩個長度的時候,我們一步走完,呀!怎麽還有一下!!
所以說,我們可以這樣想:當剩下的距離不足\(n-1\)
一定要用long long
(\(CF\)的題就這個尿性)!
恐怕上述的方法是最簡單的方法之一了吧,上代碼(有兩個細節在代碼裏註釋了):
Code
#include<iostream> using namespace std; int main() { long long n,k,s,a=1; cin>>n>>k>>s; if(s>(n-1)*k||k>s) return cout<<"NO"<<endl,0; cout<<"YES"<<endl; while(k--) { int r=min(s-k,n-1);//選區n-1與s-k中最小的,因為當s-k比n-1大的時候,我們要先消去 s-=r; if(a+r<=n)//看看往哪個方向走。 a+=r; else a-=r; cout<<a<<" "; } return 0; }
Codeforces Round #501 (Div. 3) D Walking Between Houses