时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
给定两个长度为n的整数列A和B,每次你可以从A数列的左端或右端取走一个数。假设第i次取走的数为ax,则第i次取走的数的价值vi=bi⋅ax,现在希望你求出∑vi的最大值。
输入描述:
第一行一个数T,表示有T组数据。
对于每组数据,第一行一个整数n,
接下来两行分别给出A数列与B数列。
输出描述:
每一组数据输出一行,最大的∑vi。
示例1
输入
2
2
1 1000
2 1
5
1 3 5 2 4
1 2 3 4 5
输出
2001
52
说明
对于第二个样例,
第一次从左边取走a1,v1=a1⋅b1=1,
第二次从左边取走a2,v2=a2⋅b2=6,
第三次从右边取走a5,v3=a5⋅b3=12,
第四次从右边取走a4,v4=a4⋅b4=8,
第五次取走剩下的a3,v5=a3⋅b5=25。
总价值∑vi=1+6+12+8+25=52
备注:
T≤10
1≤n≤103
1≤ai,bi≤103
分析: 取数的过程可以为:
0> 左边取零个,其余都取右边的
1 >左边取一个,其余都取右边的
2> 左边取两个,其余都取右边的
3 >左边取三个,其余都取右边的
…
..
根据这个规律,我们可以用DP来解决,用dp [ i ] [ j ] 来表明 左边取i个,右边取j个能够获得的最大值。
怎么找状态转移方程呢? 我们可以思考一下,对于dp [ i ] [ j ] 这个状态,是能够由那些状态得到的。就可以得到:
状态转移方程 :
dp[ i ] [ j ] = max(dp[ i - 1][ j ] + a[ i ] * b[ j+i ] , dp[ i ][ j -1 ] + a[ n - j +1 ] *b [ j + i ] ) .
根据这个状态转移方程我们可以得到 递推遍历的方向,首先看外层循环,对于dp[ i ] 层来说 是需要dp[ i- 1 ]层来递推,所以我们可知外层循环正向遍历i。同理内层循环 也是要正向遍历j。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 1e3+11;
const int MAXM = 1e6 ;
const LL mod = 1e9+7 ;
int a[MAXN],b[MAXN];
int dp[MAXN][MAXN];
int main(){
int T ;cin>>T;
while(T--){
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int j=1;j<=n;j++) cin>>b[j];
for(int i=1;i<=n;i++) { // 一直紧着一边拿可得到的最大值
dp[i][0]=dp[i-1][0]+a[i]*b[i];
dp[0][i]=dp[0][i-1]+a[n-i+1]*b[i];
}
int ans=0;
for(int i=1;i<=n;i++){// 外层正向遍历
for(int j=1;j<=n;j++) { // 内层也要正向遍历
dp[i][j]=max(dp[i-1][j]+a[i]*b[i+j],dp[i][j-1]+a[n-j+1]*b[j+i]) ;
if(i+j==n) ans=max(ans,dp[i][j]);
}
}
cout<<ans<<endl;
}
return 0;
}
记忆化DFS
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define CLOSE() ios_base::sync_with_stdio(false)
const int MAXN = 1e3+11;
const int MAXM = 1e6 ;
const LL mod = 1e9+7 ;
int a[MAXN],b[MAXN];
int dp[MAXN][MAXN];
int dfs(int l,int r,int step){
if(l>r) return 0;
if(dp[l][r]) return dp[l][r];
int temp=0;
temp=max(temp,dfs(l+1,r,step+1)+b[step]*a[l]);
temp=max(temp,dfs(l,r-1,step+1)+b[step]*a[r]);
return dp[l][r]=temp;
}
int main(){
CLOSE();
int T; cin>>T;
while(T--){
memset(dp,0,sizeof(dp));
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
dfs(1,n,1);
cout<<dp[1][n]<<endl;
}
return 0;
}