CF101E Candies and Stones題解

來源:互聯網
上載者:User

[題目描述]

Little Gerald and his coach Mike play an interesting game. At the beginning of the game there is a pile consisting of n candies
and a pile consisting of m stones.
Gerald and Mike move in turns, Mike goes first. During his move Mike checks how many candies and stones Gerald has eaten. Let Gerald eat a candies
and b stones.
Then Mike awards Gerald f(a, b) prize
points. Gerald during his move either eats a candy from the pile of candies or a stone from the pile of stones. As Mike sees that Gerald has eaten everything apart one candy and one stone, he awards points for the last time and the game ends. Gerald is not
allowed to eat all the candies, and he is not allowed to eat all the stones too. Tell Gerald how to play to get the largest possible number of points: it is required to find one of the possible optimal playing strategies for Gerald.

[翻譯]

         小A和小B玩遊戲,有n堆石子和m堆糖果,小B先動。

         小A的操作,取走一堆石子或一堆糖果。

         小B的操作,若截止到此輪取走了i堆石子,j堆糖果,則分值加上(xi+yj)%p

         要求:直至全部拿完,分值最大,並輸出方案(蒯自天聰)

[時限]15s

[空限]45MB

[題解]

        N^2的dp應該都知道.問題是如何在卡空間的情況下輸出方案.

        使用滾動數組是勢在必行的,但如何在使用滾動數組的情況下輸出方案呢?

        一個最裸的想法是:第一次DP到Fn+m-1,第二次重新DP到Fn+m-2,輸出方案,然後一直做N次DP,就可以輸出所有方案了.

        顯然,這樣做鐵定TLE.但是,這給我們提供了一個很好的思路.

        為了達到時間與空間的平衡,我們將DP的方程按sqrt(N)分塊,每隔sqrt(n)行把所有狀態記住.然後從後往前DP輸出方案.

        輸出方案時進行sqrt(n)次DP,每次DP時用一個sqrt(n)*m的數組記住狀態,就可以把這一段的方案搞出來了.

        因為每個狀態只會被算到2次,所以總的時間複雜度是O(n*n),空間複雜度是O(sqrt(n)*m),因為我寫的狀態是Fi,j表示選了i個有j個糖果,所以n=40000,跑起來奇慢無比(加上各種開關10s,不加開關14s).
        因為第一次打分塊,一開始塊太大,拍的資料太小,結果一直搞不出錯在哪裡,交上去全WA.

        tourist有一種很NB的方法:用Fi,j表示取了i個石頭,j個糖果.這樣空間就比我少了很多.於是,他就可以多加一個數組,記錄每sqrt(m)列的狀態!!!!

        於是,tourist的狀態就被劃分成若干sqrt(n)*sqrt(m)的子矩陣,從Fn,m遞迴下去,對每個子矩陣進行dp求出方案,只要遍曆O(n)個矩陣,總的複雜度為O(N*N+sqrt(n)*m),幾乎只有裸DP的複雜度!!!!!雖然理論的複雜度和我的一樣,但是常數完爆我的方法,時間也是我的1/3.

我的Code:

program NoName;const skip=200;type        int=longint;        arr=array[0..20000]of int;        point=^arr;var        i,j:longint;        tot,k,m,n,max,min,now:int;s,p:int;        f,g,wx,wy:arr;        prev,next,temp:point;        list:array[0..201]of arr;        ff:array[0..skip+1]of arr;        pos:array[1..201]of int;        solution:array[0..40000]of char;procedure getans(x:int);var i,j:longint;begin        fillchar(ff,sizeof(ff),0);        ff[0]:=list[x];s:=pos[x+1]-pos[x];        for i:=1 to s do begin                min:=0;max:=m;p:=i+pos[x];                if p<m then max:=p;                if(min<p-n)then min:=p-n;                for j:=min to max do begin                        if(j<>0)and(ff[i-1,j-1]>ff[i-1,j])then ff[i,j]:=ff[i-1,j-1]                                else ff[i,j]:=ff[i-1,j];                        ff[i,j]:=ff[i,j]+(wx[p-j]+wy[j])mod k;                end;        end;        for i:=pos[x+1]-1 downto pos[x] do begin                s:=i-pos[x];                if(now=0)or(ff[s,now]>ff[s,now-1])then begin                        solution[i]:='C';                end else begin                        solution[i]:='S';dec(now);                end;        end;end;procedure dp;begin        f[0]:=(wx[0]+wy[0])mod k;        prev:=@f;next:=@g;        tot:=1;list[1]:=f;        for i:=1 to n+m do begin                min:=0;max:=m;                if i<m then max:=i;                if(min<i-n)then min:=i-n;                for j:=min to max do begin                        if(j<>0)and(prev^[j]<prev^[j-1])then next^[j]:=prev^[j-1]                                else next^[j]:=prev^[j];                        next^[j]:=next^[j]+(wx[i-j]+wy[j])mod k;                end;                if(i mod skip=0)and(i<>n+m)then begin                        inc(tot);                        for j:=min to max do list[tot][j]:=next^[j];                        pos[tot]:=i;                end;                temp:=prev;prev:=next;next:=temp;        end;        writeln(prev^[m]);        inc(tot);list[tot]:=prev^;pos[tot]:=n+m;        now:=m;        for i:=tot-1 downto 1 do getans(i);        for i:=0 to n+m-1 do write(solution[i]);end;begin        assign(input,'E.in');reset(input);        assign(output,'E.out');rewrite(output);        read(n,m,k);        dec(n);dec(m);        for i:=0 to n do read(wx[i]);        for i:=0 to m do read(wy[i]);        dp;        close(input);close(output);end.

tourist的程式自己去CF上看吧.

BY QW

轉載請註明出處

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.