D. Maximum Sum of Products(二维数组记录改变区间)

Problem - 1519D - Codeforces

 

给你两个长度为n的整数数组a和b。

你最多可以扭转数组a的一个子数组(连续子段)。

你的任务是反转这样一个子数组,使其总和∑i=1nai⋅bi达到最大。

输入
第一行包含一个整数n(1≤n≤5000)。

第二行包含n个整数a1,a2,...,an(1≤ai≤107)。

第三行包含n个整数b1,b2,...,bn(1≤bi≤107)。

输出


例子
输入复制
5
2 3 2 1 3
1 3 2 4 2
输出拷贝
29
输入复制
2
13 37
2 4
输出拷贝
174
输入复制
6
1 8 7 6 3 6
5 9 6 8 8 6
输出拷贝
235
注意
在第一个例子中,你可以反转子数组[4,5]。然后a=[2,3,2,3,1],2⋅1+3⋅3+2⋅2+3⋅4+1⋅2=29。

在第二个例子中,你不需要使用反向运算。13⋅2+37⋅4=174.

在第三个例子中,你可以反转子数组[3,5]。那么a=[1,8,3,6,7,6],1⋅5+8⋅9+3⋅6+6⋅8+7⋅8+6⋅6=235。

题解:

贪心肯定是写不了这道题的,

我们如果暴力枚举所有可能区间的开头与结尾,然后再计算区间内交换的值也不行

肯定会t

那我们想想如何来优化这个过程,

首先前缀和是容易想到的,对于没有改变的区间可以快速求值

我们可以发现一些交换过的区间,可能会再次用到,

如果我们可以记录每次改变的区间,再次用到时就不用再次计算

因此我们用一个二维数组

f[l][r],代表记录的反转al~r后相乘后的值

每次dfs(i,j)我们要改变的区间,每次dfs的同时记录f[l][r]

#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define int long long
int a[200050];
int b[200050];
int p[200059];
int f[5005][5005];
int dfs(int l,int r)
{
	if(l == r)
	{
		return a[l]*b[r];
	}
	else if(l + 1 ==r)
	{
		return a[l]*b[r] + a[r]*b[l];
	}
	if(f[l][r] != 0)
	return f[l][r];
	return f[l][r] = a[l]*b[r] + a[r]*b[l] +dfs(l+1,r-1);
}
void solve()
{
	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++)
	{
		p[i] = p[i-1] + a[i]*b[i];
	}
	int ans = 0;
	for(int i = 1;i <= n;i++)
	{
		for(int j = i;j <= n;j++)
		{
			ans = max(ans,p[n] - p[j] + p[i-1] + dfs(i,j));
		}
	}
	cout << ans<<"\n";
	 
	
}
//1,0,1,1,0,1
//1 6
//3 2
//4 6
//5 3
//4 4
//5
signed main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);
//	cout.tie(0);
	int t = 1;
//	cin >> t;
    while(t--)
	{
		solve();
	} 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值