您的位置:首页 > 其它

srm 654 div2 1000 (DP,最大连续和拓展, 有亮点)

2015-03-26 23:13 525 查看
题意:

有 a1 - a2 - … - an 这样的式子,最多加两个括号,使得和最大。

比如 1-3-3-4-5

变成 1-(3-3-4-5) = 10

思路:

1)加一个括号

把括号打开得到

a1−a2−...−ai+ai+1+...+aj−aj+1−...−ana_1 - a_2 - ...-a_i + a_{i+1} +...+ a_j - a_{j+1} - ... -a_n

就是求最大连续和

2)加两个括号 (两个括号嵌套和分开)

同理,我们把括号打开可以得到两段求和

于是,任务变成了从 a3...ana_3...a_n求两段或一段最大连续和

PS:

看到一种非常简洁的做法, 非常值得思考!!

// dp[0]...dp[4] 分别代表从没有括号到有两个括号,
// 且最后是连续的减号这5种情况
int dp[5], tmp[5];
for (int i=2;i<n;++i) {
tmp[0] = dp[0] - a[i];
tmp[1] = max (dp[0], dp[1]) + a[i];
tmp[2] = max (dp[1], dp[2]) + a[i];
tmp[3] = max (dp[2], dp[3]) + a[i];
tmp[4] = max (dp[3], dp[4]) + a[i];
for (int j=0;j<5;++j) dp[j] = tmp[j];
}
int mx = -inf;for (int i=0;i<5;++i) mx = max (mx, dp[i]);
int ans = mx + a[0] - a[1];


const int Maxn = 2000;

int dp[2][Maxn+5], L[Maxn+5], R[Maxn+5];

class SuccessiveSubtraction2
{
public:
int go (vector<int> &a) {
int n = a.size();
vector<int> pre(n+5);
pre[1] = a[0];rep(i, 2, n) pre[i] = pre[i-1] - a[i-1];
if (n < 3) return pre
;
dp[0][3] = a[2];
rep(i, 4, n) dp[0][i] = max (dp[0][i-1]+a[i-1], a[i-1]);
dp[1]
= a[n-1];
urep(i, n-1, 3) dp[1][i] = max (dp[1][i+1]+a[i-1], a[i-1]);
L[2] = 0;rep(i, 3, n) L[i] = max (L[i-1], dp[0][i]);
// 当连续和为负的时候,变号没有意义
// 用0来代替它,表示不取
R[n+1] = 0;urep(i, n, 3) R[i] = max (R[i+1], dp[1][i]);
int mx = max (0, max (R[3], L
));
rep(i, 3, n-1) mx = max (mx, max (L[i], 0) + max (R[i+1], 0));
return pre
+ mx*2;
}

vector <int> calc(vector <int> a, vector <int> p, vector <int> v)
{
vector<int> ans;
for (int i=0;i<p.size();++i) {
a[p[i]] = v[i];
ans.push_back(go(a));
}
return ans;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: