1. 程式人生 > >Codeforces Round #501 (Div. 3) D Walking Between Houses

Codeforces Round #501 (Div. 3) D Walking Between Houses

端點 你是 pre n) main 選區 賽後 str 但是

翻譯

給你一條數軸(出題人很喜歡數軸啊),上面有排列著\(n\)個點,編號為\(1\)\(n\)(你開始在\(1\))。每次你要從一個點移動到另一個點(可以重復)。移動距離為兩點坐標之差的絕對值,問你是否能否在\(k\)次機會內裏一共移動\(s\)距離,並輸出方案。

思路

第四題還是比較難的,賽後想了幾分鐘時才有頭緒。

毫無疑問還是貪心(出題人很喜歡貪心啊)!那麽我們分類討論,先看不合法的情況

  • 無論如何走你也走不到那個距離

  • 無論如何走你也會走超那個距離

看來只要能走到那個距離除外都是不合法的,因此就一個走超和走不到(我沒廢話!)。

那麽如何解決?很簡單,走不到就是每次你從最左邊走到最右邊,再從最右邊走到最左邊,這樣循環下去,一直到你走完了還不到。

走超了就是你每次走一個距離,進行\(k\)次後還是大於\(s\)

那麽這兩個代碼好寫極了,不用我教你吧\(^_^\)

到了合法的情況,受到不合法的啟發,我們可以想到這樣的方法:每一次啊,先從最左邊走到最右邊,再從最右邊走到最左邊,循環下去,一直到你剩下的距離不足\(n-1\)(\(n-1\)就是數軸兩個端點間的距離)的時候啊,直接走完即可(由於在此期間你只會位於數軸的兩個端點)。

但是不會那麽簡單的\(QAQ\),直接走完可不行啊,如果要走\(32\)那麽遠,\(4\)下子走完,數軸有\(11\)個點。照我們說的,當還有兩個長度的時候,我們一步走完,呀!怎麽還有一下!!

所以說,我們可以這樣想:當剩下的距離不足\(n-1\)

的時候,我們嘗試分成多部走,很多種方法,我的有點麻煩,某位大佬寫的是:走\(s-k\)\(s\)是剩下的距離)的步數。感覺自己恍然大悟了(不懂你可以算算,由於是\(s-k\),這樣就巧妙的拆分成了多部分)!

一定要用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