← 所有笔记

D. Maximum Sum of Products

D. Maximum Sum of Products Educational Codeforces Round 108 (Rated for Div. 2) 区间dp,前缀和

题目传送门

题目大意:

给两个字符a,b,在a中选一段连续子串,将其倒置(可以不选),计算ai*bi之和的最大值。

思路:

先计算前缀和,然后区间dp,枚举区间长度len,然后枚举左端点l,确定右端点r,将区间内的a倒置,判断区间内的值与未倒置之前的(s[r]-s[l-1])值差,取max,如果max大于0,则答案为s[n]+max,否则答案为s[n];

状态转移方程:

f[l][r]=f[l+1][r-1]+左端点+右端点

  • 注意f[i][j]表示的是将区间内倒置的值,计算左端点和右端点的时候需要注意。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5005;
#define pii pair<int,int>
#define endl "\n"
#define ll long long
#define inf 0x3f3f3f3f
ll f[maxn][maxn];
ll s[maxn], a[maxn],b[maxn];
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n;
    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++)
        s[i] = s[i - 1] + a[i] * b[i];
    for (int i = 1; i <= n; i++) f[i][i] = a[i] * b[i]; 
    // 为什么这样初始化呢,因为中间的值不会改变,比如
    //f[1][3]=f[2][2]+左+右
    ll gap = 0;
    for (int len = 2; len <= n; len++)
    {
        for (int i = 1; i+len-1<=n; i++)
        {
            int l = i, r = i + len - 1;
            int temp = l + r;
            f[l][r]= f[l+1][r-1]+a[l] * b[temp-l] + b[temp-r] * a[r];
            gap = max(gap,f[l][r] - s[r] + s[l - 1]);
        }
    }
    if (gap > 0) cout << s[n] + gap << endl;
    else cout << s[n]<<endl;
    return 0;
}
✳

谢谢你读到这里。

更新于 2022-07-15

搜索笔记

搜索文章标题、标签和正文。

↑ ↓ 选择 · Enter 阅读Esc 关闭