SRM 269 DIV1 Hard PieSharing
問題
Nつに分割されたパイがある。Nは3の倍数である。そのそれぞれの部分の面積piecesが与えられる。
これを自分と相手で交互に食べ、自分が食べる面積を最大化したい。
自分は、任意の部分を1つ選び、それを食べることができる。
次に、相手は直前に自分が食べた部分の両隣のパイを2つとも食べなければいけない。
これを繰り返す。
食べられる最大の面積を求めよ
- 3 <= N <= 48
- 1 <= pieces[i] <= 100
- sum pieces = 100
解答
Editorialを参考にした。
自分の食べるパイ(N/3)つを最初に選択するという考え方をする。
まず、明らかに、どれか2つが隣接しているような選び方では食べられない。それを食べようとするとその隣を食べられてしまうので。
逆に、どれも隣接していないような(N/3)つの選び方ならば必ず食べることが出来る。
直感的には、選択パイの数は少ないので常に隙間が多く、隙間を維持したところを食べられる感じ。
さてこの組み合わせを選ぶのは普通に円DPすればいい
コード
#include <vector> #include <cstring> #define mset(m,v) memset(m,v,sizeof(m)) #define INF 0x3f3f3f3f using namespace std; typedef vector<int> vi; int dp[2][55][20]; struct PieSharing { vi p; int n; int rec(bool leftmost, int i, int count) { if(dp[leftmost][i][count] != -1) return dp[leftmost][i][count]; int r = -INF; if(i == n) { if(count == 0) r = 0; else ; } else if(i == n-1) { if(leftmost) r = max(r, rec(leftmost, i+1, count)); else { r = max(r, rec(leftmost, i+1, count)); if(count) r = max(r, p[i]+rec(leftmost, i+1, count-1)); } }else { r = max(r, rec(leftmost, i+1, count)); if(count) r = max(r, p[i]+rec(leftmost, i+2, count-1)); } return dp[leftmost][i][count] = r; } int share(vector <int> pieces) { p = pieces; n = p.size(); mset(dp, -1); return max(p[0]+rec(true, 2, n/3-1), rec(false, 1, n/3)); } };