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;
}

浙公网安备 33010602011771号