Maximum Sum of Products

传送门

题意:
两个序列a, b, 可以对a序列中的一个子序列进行翻转操作,求max\(\sum\limits_{i = 1}^{n}a_i * b_i\)


思路:
首先,可以想到的是肯定存在唯一的一个区间,得到答案,暴力枚举这个区间,对于不翻转的地方,可以直接前缀和求得,对于翻转的地方,要是也能够\(O(1)\)求得,那就是\(O(n^2)\),能过,所以问题就是求这个翻转区间,对于每一个区间,如果只有一个元素那就是\(a_i * b_i\), 如果有多个元素,比如3个元素,其实是可以从1个元素转移过来的,n个元素,可以从n - 2个元素转移过来,具体的转移为\(resum[l][r] = resum[l + 1][r] + a[l] * b[r] + a[r] * b[l]\), 对于len >= 3都可以,对于len = 2, 也是可以的,因为resum[l + 1][r] == 0, 由前一个长度转移过来,这就是区间dp, resum求好即可


总结:
区间dp, 其实就是枚举长度的转移,从前一个长度转移,需要用的长度即可得到答案

点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;

typedef long long ll;
const ll MAXN = 5e3 + 10;
ll n;
ll a[MAXN], b[MAXN], sum[MAXN], resum[MAXN][MAXN];

int main()
{
    IOS; cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
        cin >> b[i];
    for (int i = 1; i <= n; ++i)
        sum[i] = sum[i - 1] + a[i] * b[i], resum[i][i] = a[i] * b[i];   
    for (int len = 2; len <= n; ++len)
        for (int l = 1, r; l + len - 1 <= n; ++l)
            r = l + len - 1, resum[l][r] = resum[l + 1][r - 1] + a[l] * b[r] + a[r] * b[l];
    ll ans = 0;   
    for (int l = 1; l <= n; ++l)
    {
        for (int r = l; r <= n; ++r)
        {
            ll tempsum = sum[l - 1] + sum[n] - sum[r] + resum[l][r];
            ans = max(ans, tempsum);
        }
    }
    cout << ans << endl;
    return 0;
}

posted @ 2022-10-18 20:39  YUGUOTIANQING  阅读(80)  评论(0)    收藏  举报