AcWing277 饼干 题解
今日もいい天気☆
首先有一个显而易见的贪心:我们要把饼干分的尽量均匀的同时,多出来的饼干尽量给贪婪值大的.
也就是说对贪婪值由大到小排序后,饼干数量应该也是单调不升的,所以显然我们最开始要排序
于是我们根据题意设计状态,即:
$ f[i][j]= $ \(i\)个孩子分\(j\)块饼干产生的怒气值最小值
转移:
给原来的$ i \(个孩子每人分一块饼干,这种情况下\) f $不变,因为排名没有任何变化
也就是$ f[i][j]=f[i][j-i] $
原来有\(k\)人,新加入$ i-k $个人每人分到一个饼干
也就是$ f[i][j]=f[k][j-(i-k)]+k\times\sum^i_{x=k+1}s_x $
显然,这个和我们只需要前缀和就能轻松实现
初值:
赋最大值(我才不会告诉你我因为没赋最大值卡了五分钟)
显然\(0\)个人分\(0\)饼干怨气也是\(0\) 所以\(f[0][0]=0\)
最后输出\(f[n][m]\)即为答案
接下来考虑第二小问,我们用两个数组\(g1\),\(g2\)分别记录转移前的状态,即对于情况\(1\)是\(i\), \(j-i\),情况\(2\)是\(k\), \(j-(i-k)\)
然后往前递归即可,当遇到情况\(1\)(即\(g1=i\)时)就让前面\(i\)个全加\(1\),遇到情况\(2\)时(即非情况1)就把从\(g1+1\)到\(i\)全设为\(1\)
这题最坑的点是数据没有输出方案
/*
* @Author: 2019yyy
* @Date: 2022-12-27 22:07:17
* @LastEditors: 2019yyy
* @LastEditTime: 2022-12-27 22:20:58
* @FilePath: \code\acwing\277.cpp
* @Description:
*
* I love Chtholly forever
*/#include<bits/stdc++.h>
using namespace std;
int sum[5100],f[51][5100];
int g1[51][5100],g2[51][5100],ans[5100];
struct Node{
int val,id;
const bool operator<(Node another){
return val>another.val;
}
}a[5100];
void fun(int x,int y){
if(x==0){
return;
}
fun(g1[x][y],g2[x][y]);
if(x==g1[x][y]){
for(int i=1;i<=x;i++){
ans[a[i].id]++;
}
}else{
for(int i=g1[x][y]+1;i<=x;i++){
ans[a[i].id]=1;
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].val;
a[i].id=i;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i].val;
}
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=m;j++){
for(int k=0;k<i;k++){
if(f[k][j-(i-k)]+k*(sum[i]-sum[k])<f[i][j]){
f[i][j]=f[k][j-(i-k)]+k*(sum[i]-sum[k]);
g1[i][j]=k;
g2[i][j]=j-(i-k);
}
}
if(f[i][j-i]<f[i][j]){
f[i][j]=f[i][j-i];
g1[i][j]=i;
g2[i][j]=j-i;
}
}
}
cout<<f[n][m]<<'\n';
fun(n,m);
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
return 0;
}

浙公网安备 33010602011771号