一本通OJ-生日欢唱

生日欢唱

题意

n个男,n个女排成两列。可以选择上来唱歌获得 $ a[i]*b[j]$ 的价值,否则若男 \(or\) 女连续不上来损失 \((\sum a[i]) ^ 2\)的价值。可以上来也可以不上来。求最大价值。

分析

显然是区间dp,考虑\(f[i][j]\)表示考虑前\(i\)个男生,前\(j\)个女生并且强制让\(i,j\)对唱最大价值。有转移如下。

不难考虑可以使一部分男生/女生不上来。则有 \(f[i][j]=max(f[k][j-1]+a[i]*b[j]-\sum a[s])\)

同理有女生。

最后强制令\(n+1\)价值都为0,强制匹配,答案为\(f[n+1][n+1]\)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
const int N=310;
int a[N],suma[N],b[N],sumb[N];
int f[N][N];
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        suma[i]=suma[i-1]+a[i];
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&b[i]);
        sumb[i]=sumb[i-1]+b[i];
    }
    suma[n+1]=suma[n],sumb[n+1]=sumb[n];
    for(int i=1;i<=n;i++){
        f[1][i]=a[1]*b[i]-(sumb[i-1]-sumb[0])*(sumb[i-1]-sumb[0]);
        f[i][1]=a[i]*b[1]-(suma[i-1]-suma[0])*(suma[i-1]-suma[0]);
    }
    for(int i=2;i<=n+1;i++){
        for(int j=2;j<=n+1;j++){
            for(int k=1;k<i;k++){
                f[i][j]=max(f[i][j],f[k][j-1]+a[i]*b[j]-(suma[i-1]-suma[k])*(suma[i-1]-suma[k]));
            }
            for(int k=1;k<j;k++){
                f[i][j]=max(f[i][j],f[i-1][k]+a[i]*b[j]-(sumb[j-1]-sumb[k])*(sumb[j-1]-sumb[k]));
            }
        }
    }
    printf("%lld",f[n+1][n+1]);
    return 0;
}
posted @ 2023-07-25 13:51  Zimo_666  阅读(11)  评论(0编辑  收藏  举报