P14922 [GESP202512 七级] 学习小组

题目

传送门

思路

借鉴了洛谷题解区的第一篇题解

状态定义

设dp[i][j]为分了 i 个人数超过一人的小组且已选择了j人时,最大的讨论积极度。那么我们怎么选择人呢?我们可以从小到大排序,每次取头尾两个两个,剩下的在中间取。这样子我们的差就是最大的,记得取最大值和最小值相减。

转移方程

dp[i-1][j-k]+a[k]+max(c[n-i+1],c[i])-min(c[n-i+1],c[i]));前提是当k>=2。

当k==1的时候我们取dp[i][j]=dp[i-1][j-1]+a[1];上一组的当前减一人的最大的讨论积极度+a[1]。

答案

for(int i=1;i<=n;++i){
        ans=max(ans,dp[i][n]);
}

在满足n个人的i人数大于1的小组里寻找最大值。

代码

有注释版

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
int n,c[maxn],a[maxn],dp[maxn][maxn];
int main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>c[i];
    }
    for(int i=1;i<=n;++i){
        cin>>a[i];
    }
    sort(c+1,c+n+1);//排序 
    for(int i=1;i<=n;++i){
        for(int j=i;j<=n;++j){//至少有i个人 
            dp[i][j]=dp[i-1][j-1]+a[1];
            for(int k=2;k<=j;++k){
                dp[i][j]=max(dp[i][j],dp[i-1][j-k]+a[k]+max(c[n-i+1],c[i])-min(c[n-i+1],c[i]));
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i){
        ans=max(ans,dp[i][n]);//寻找答案 
    }
    cout<<ans<<endl;
    return 0;
}

无注释版

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
int n,c[maxn],a[maxn],dp[maxn][maxn];
int main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>c[i];
    }
    for(int i=1;i<=n;++i){
        cin>>a[i];
    }
    sort(c+1,c+n+1); 
    for(int i=1;i<=n;++i){
        for(int j=i;j<=n;++j){
            dp[i][j]=dp[i-1][j-1]+a[1];
            for(int k=2;k<=j;++k){
                dp[i][j]=max(dp[i][j],dp[i-1][j-k]+a[k]+max(c[n-i+1],c[i])-min(c[n-i+1],c[i]));
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i){
        ans=max(ans,dp[i][n]);
    }
    cout<<ans<<endl;
    return 0;
}

完结撒花

posted @ 2026-09-06 18:10  陈晨2011  阅读(6)  评论(0)    收藏  举报