1. 程式人生 > >ZCC loves meat

ZCC loves meat

題目描述

ZCC終於打開了密碼箱,發現裡面只是一堆風乾的肉條,於是他打算喂狗。

ZCC養了n條狗,有m根肉條,他想把肉條一根不留地分給狗,並使得每條狗至少有一條肉條可吃。狗總是很貪心,它們不希望看到有其他的狗有更多的肉條,否則就會不開心。一條狗的不開心程度可以表示為他的貪心程度和擁有比它更多肉條的狗的數量的乘積。現在ZCC想知道一種分配方式使得狗們的不開心程度的和最小。

題解

這題非常玄妙,看到這道題有沒有想到整數劃分?沒有想到就可以自閉了(想到了也自閉了)。然後我們可以用類似的方法DP。顯然我們先排序,這裡降序排。

  1. f
    [ i ] [ j ] f[i][j]
    表示做到第 i
    i
    個,用了 j j 塊肉的狀態。假如第 i i 塊用了大於1塊的肉則這個狀態和 f
    [ i ] [ j i ] f[i][j-i]
    是一樣的,全部取掉1。
  2. 假如不是1,那麼列舉和它相連的有幾個1

f [ i ] [ j ] = m i n ( f [ i ] [ j i ] , f [ k ] [ j ( i k ) ] + k ( s u m [ i ] s u m [ k ] ) ) f[i][j]=min(f[i][j-i],f[k][j-(i-k)]+k*(sum[i]-sum[k]))

我們還要求方案,顯然記錄下來方案的路徑
如果兩個方案的 i i 相同說明是從所有減1轉移來的,要全部加1
反正說明是從前面一些位置全是1轉移過來的,那些位置加1即可

程式碼

#include <bits/stdc++.h>
#define maxn 55
#define MAXN 5005
#define INF 0x3f3f3f3f
#define LL long long
#define P pair<int,int>
#define MP make_pair
using namespace std;
int read(){
    int res,f=1; char c;
    while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48);
    while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
    return res*f;
}
int n,m,ans[maxn],D[maxn],d[maxn],g[maxn],f[maxn][MAXN],sum[maxn];
bool cmp(int x,int y){return g[x]>g[y];}
P path[maxn][MAXN];
int main(){
    memset(f,0x3f,sizeof f);
    n=read(); m=read();
    for(int i=1;i<=n;i++) d[i]=i,g[i]=read();
    stable_sort(d+1,d+n+1,cmp);
    for(int i=1;i<=n;i++) sum[i]=g[d[i]]+sum[i-1];
    f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=m;j++){
            f[i][j]=f[i][j-i];
            path[i][j]=MP(i,j-i);
            for(int k=0;k<i;k++){
                if(f[i][j]>f[k][j-(i-k)]+k*(sum[i]-sum[k])){
                    f[i][j]=f[k][j-(i-k)]+k*(sum[i]-sum[k]);
                    path[i][j]=MP(k,j-(i-k));
                }
            }
        }
    }
    printf("%d\n",f[n][m]);
    P x=MP(n,m);
    while(x.first && x.second){
        P y=path[x.first][x.second];
        if(x.first==y.first) for(int i=1;i<=x.first;i++) ans[d[i]]++;
        else for(int i=y.first+1;i<=x.first;i++) ans[d[i]]++;
        x=y;
    }
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}