描述
圣诞老人共有M个饼干,准备全部分给N个孩子。每个孩子有一个贪婪度,第 i 个孩子的贪婪度为 g[i]。如果有 a[i] 个孩子拿到的饼干数比第 i 个孩子多,那么第 i 个孩子会产生 g[i]*a[i]的怨气。给定N、M和序列g,圣诞老人请你帮他安排一种分配方式,使得每个孩子至少分到一块饼干,并且所有孩子的怨气总和最小。1≤N≤30, N≤M≤5000, 1<=gi<=10^7。输入格式
第一行两个整数N,M,第二行N个整数g1~gN。输出格式
第一行一个整数表示答案,第二行N个整数表示每个孩子分到的饼干数。本题有SPJ,若有多种方案,输出任意一种均可。样例输入
样例输入1
3 20
1 2 3样例输入2
4 9
2 1 5 8
样例输出
样例输出1
2
2 9 9样例输出2
7
2 1 3 3
来源
ITMO
简单dp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define fr first
#define se second
#define ll long long
int f[31][5010];//i个人分j个
int n,m;
struct data{
int id,num;
}g[31];
P from[31][5010];
int sum[31] , ans[31];
int read()
{
int sum = 0;char c = getchar();bool flag = true;
while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
if(flag) return sum;
else return -sum;
}
bool mycmp(data a,data b)
{
return a.num > b.num;
}
int main()
{
n = read();m = read();rep(i,0,n) rep(j,0,m) f[i][j] = 1e9;
rep(i,1,n) g[i].num = read() , g[i].id = i;
sort(g+1,g+n+1,mycmp);
rep(i,1,n) sum[i] = sum[i-1] + g[i].num;
f[0][0] = 0;
rep(i,1,n)
rep(j,i,m)
{
f[i][j] = f[i][j-i];
from[i][j].fr = i;from[i][j].se = j-i;
rep(k,0,i-1)
{
int tmp = sum[i] - sum[k];tmp*=k;
if(f[k][j-i+k]+tmp < f[i][j])
{
f[i][j] = f[k][j-i+k] + tmp;
from[i][j].fr = k;from[i][j].se = j-i+k;
}
}
}
printf("%d\n",f[n][m]);
P now;
now.fr = n;now.se = m;
int det = 0;
while(now.fr != 0)
{
int x = now.fr,y = now.se;
if(from[x][y].fr == x) det++;
else if(from[x][y].fr == x-1)ans[g[x].id] = y - from[x][y].se + det;
else if(from[x][y].fr < x-1)
{
rep(i,from[x][y].fr+1,x) ans[g[i].id] = 1 + det;
}
now = from[x][y];
}
rep(i,1,n) printf("%d ",ans[i]);
return 0;
}