题解 CF1195C 【Basketball Exercise】

小黑AWM

2019-07-18 09:21:00

Solution

简单的线性的DP,一眼看出状态后很容易可以写掉,但是题意可能会有导向性错误导致想到 $O(n^2)$ 的算法。 约定:记 $h(x,y)$ 为第 $x$ 列,第 $y$ 行的人的身高。 第 $i$ 列我们考虑有三种状态:选第一个,选第二个,不选。由于题意限制,我们需要考虑是否连续两个选的在同一行。 不难发现除了当前这列和之前这列我们需要考虑,更前面的状态都已经没有用了,那么这满足了无后效性的要求。 我们给出最大的子方案一定能使的总方案最大,所以也满足最优子结构的性质。 根据之前的考虑设计状态 $f(i,\space k)$ 表示选到第 $i$ 列,每列选了第 $k$ 行的人时的最大身高和,当 $k=0$ 时表示这列不选。 由状态直接得到状态转移方程,不需要优化可以直接线性DP。 $$f(i ,k) = max\{f(i-1,j)+h(i,k)\},j\in \{0,1,2\}$$ 且 $j$ 和 $k$ 应满足 $j \not = k$ 或 $j=k=0$ 那么最终答案就是 $max\{f(n,0),f(n,1),f(n,2)\}$ 实现并没有难度。 ```cpp /* * Author: xiaohei_AWM * Date: 7.17 * Mutto: Face to the weakness, expect for the strength. */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define reg register #define endfile fclose(stdin);fclose(stdout); typedef long long ll; typedef unsigned long long ull; typedef double db; typedef std::pair<int,int> pii; typedef std::pair<ll,ll> pll; namespace IO{ char buf[1<<15],*S,*T; inline char gc(){ if (S==T){ T=(S=buf)+fread(buf,1,1<<15,stdin); if (S==T)return EOF; } return *S++; } inline int read(){ reg int x;reg bool f;reg char c; for(f=0;(c=gc())<'0'||c>'9';f=c=='-'); for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0')); return f?-x:x; } inline ll readll(){ reg ll x;reg bool f;reg char c; for(f=0;(c=gc())<'0'||c>'9';f=c=='-'); for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0')); return f?-x:x; } } using namespace IO; const int maxn = 1e5 + 10; int n;//f[i][j]表示选到第i个人,那人是j状态的最大答案 ll h[3][maxn], f[maxn][3]; int main(){ n = read(); for(int i = 1; i <= n; i++) h[1][i] = read(); for(int i = 1; i <= n; i++) h[2][i] = read(); for(int i = 1; i <= n; i++){ for(int j = 0; j <= 2; j++){ for(int k = 0; k <= 2; k++){ if(j == k && j != 0) continue; f[i][j] = max(f[i][j], f[i-1][k] + h[j][i]); } } } cout << max(f[n][0], max(f[n][1], f[n][2])) << endl; return 0; } ```