D. Maximum Sum of Products
题目大意:
给定两个长为 n 的序列 a 和 b。你可以对 a 的一段区间翻转,也可以不翻转,要求翻转后 a 与 b 对应位置之积的和最大。即求下式的值最大:
∑
i
=
1
n
a
i
∗
b
i
\sum_{i=1}^{n}a_i*b_i
i=1∑nai∗bi
思路:
首先考虑暴力,枚举每一个区间翻转,并进行求和,显然时间复杂度
O
(
N
3
)
O(N^3)
O(N3)会爆哎。
那不写除了暴力我还会个啥
其实呢,我们还可以得出一个小小的结论,就是每次交换后的答案所改变的值
假设我们交换
a
i
a_i
ai和
a
j
a_j
aj那么其改变量即为:
a
i
×
b
j
+
a
j
×
b
i
−
a
i
×
b
i
−
a
j
×
b
j
a_i×b_j+a_j×b_i-a_i×b_i-a_j×b_j
ai×bj+aj×bi−ai×bi−aj×bj
即为
(
a
i
−
a
j
)
×
(
b
j
−
b
i
)
(a_i-a_j)×(b_j-b_i)
(ai−aj)×(bj−bi)
那么此时我们脑海中就又出现了一个奇妙的想法,我们可不可以利用这个结论,通过扩张区间的操作来达到求出最大值呢
恶补考斯 耶斯(of course yes)
那么我们只需要枚举每一个区间的起点,但是区间有长度为奇数的,也有长度为偶数的,所以我们要分别枚举当区间以一个数为起点和以两个数为起点时的情况,累计求出改变的最大值,与初始值相加即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<sstream>
#include<queue>
#define fr for
#define pi 3.1415926535
#define me(a,b,c) memset(a,b,sizeof c)
#define cut cout
#define eps 0.00000001
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
ll a[N];
map<int, int>mp;
ll b[N];
int main() {
int n;
cin >> n;
ll sum = 0;
fr(int i = 1; i <= n; i++)cin >> a[i];
fr(int i = 1; i <= n; i++)cin >> b[i], sum += b[i]*a[i];
ll h = 0;
//起点为一个数(区间长度为奇数)
fr(int i = 1; i <= n; i++) {
ll h1 = 0;
fr(int j = i, k = i; j >= 1 && k <= n; j--, k++) {
h1 += (a[j] - a[k]) * (b[k] - b[j]);
h = max(h, h1);
}
}
//起点为两个数(区间长度为偶数)
fr(int i = 1; i <= n; i++) {
ll h2 = 0;
fr(int j = i, k = i+1; j >= 1 && k <= n; j--, k++) {
h2 += (a[j] - a[k]) * (b[k] - b[j]);
h = max(h, h2);
}
}
cut << sum + h << endl;
}
还有一种类似区间dp的做法,我蒻蒟本蒻不是太会
大概状态方程为
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
+
1
]
+
(
a
i
−
a
j
)
×
(
b
j
−
b
i
)
dp[i][j]=dp[i-1][j+1]+(a_i-a_j)×(b_j-b_i)
dp[i][j]=dp[i−1][j+1]+(ai−aj)×(bj−bi)