$ CH 5105 Cookies $



$ solution: $

真是好题一道!这道题我想了很久很久,就得这一题可以直接完全贪心,可惜最后还是失败了,但是对贪心的深入思考也换来了一个最优解方案。然后这一题的DP也考的很有技术!

贪心1:这一道题当时第一眼就是贪心。首先不管每一个孩子的贪婪度,只要我们将糖果分为 $ N $ 份,实际上就已经确定了会存在多少个孩子他们的糖果数比多少个其他孩子要少。于是我们贪心的让贪婪度小的孩子去做那些糖果数比多少个其他孩子要少的孩子。(虽然这在伦理上说不过去)

贪心2,它可以减少数据范围:如果某些孩子的糖果数一样那么他们彼此之间就不会产生怨气。所以当我们将糖果平均分时,产生的怨气最少(就是没有怨气)。但是我们的糖果数不一定就能平均分了,但是我们依旧可以贪心的让相同糖果数的人尽量多。其次我们可以想到:如果糖果不够平均分,那么一定存在几个人他们的糖果数比其他所有人都低!这样我们就能产生一个很自然的想法:先平均分,如果还剩下几个不够让所有的孩子在多拿一个糖果,就钦定从贪婪度嘴小的孩子里拿回糖果给其他的孩子使得除了这个孩子以外其他孩子都是平均分的(真的好不公平啊),这样肯定能最优。但是我们同样不能保证把这个孩子的所有糖果都拿回能使得(除了这个孩子以外其他孩子都是平均分的)。但是这种情况在 $ m>n^2 $ 的时候可以得到保证,多以我们可以将 $ m $ 限制在 $ n^2 $ 以内,于是数据范围就被我们消减了,然后博主就拿到了CH上的最优解。。。。。。

然后讲一下DP,这道题的DP比较难想,因为我们首先需要想到第一个贪心,然后我们发现贪婪度小的孩子分的糖果少,于是我们按照贪婪度从大到小排序,这就符合我们线性DP的要求了。我完全可以设 $ F[i][j] $ 表示前 $ i $ 个孩子用了 $ j $ 颗糖果。但是这一题DP也难快速转移,我们如果正常转移花费的时间很多,会超时(如果我们用第二个贪心减少数据范围,也可以跑过去)。于是我们需要优化,这时候我们发现由于后面的孩子因为贪婪度小分到的糖果少一些,于是我们可以转移一下:假如第 $ i+1 $ 个孩子比第 $ i $ 个孩子得到的糖果少一个,那么这就相当于前 $ i $ 个孩子都多拿了一个糖果(这两个想法是等效的)。于是转移方程变成了:

$ F[i][j]={{F[i][j-i]}_{{ min}_{0\leq k<i}{F[k][j-(i-k)]+k\times (S[i]-S[k]) }}} $

注: $ S[i] $ 表示前 $ i $ 个孩子的贪婪度总和。



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int using namespace std; int n,m;
int S[35];
int as[35];
int f[35][905]; struct su{
int da,id;
inline bool operator <(const su &x)const{return da>x.da;}
}a[35]; struct pi{
int x,y;
}d[35][905]; inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
return sign?-res:res;
} inline void tepan(){
printf("%d\n",a[n].da*(n-1));
rg ans=m/n,res=m%n;
for(rg i=1;i<n;++i) as[a[i].id]=ans+bool(res);
as[a[n].id]=ans; if(res) as[a[n].id]-=n-res-1;
for(rg i=1;i<=n;++i) printf("%d ",as[i]);
puts(""); exit(0);
} inline void print(int i,int j){
if(i==0)return ;
else print(d[i][j].x,d[i][j].y);
if(d[i][j].x==i) for(rg k=1;k<=i;++k)++as[a[k].id];
else for(rg k=d[i][j].x+1;k<=i;++k)++as[a[k].id];
} int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=qr(); m=qr();
for(rg i=1;i<=n;++i)
a[i].da=qr(),a[i].id=i;
sort(a+1,a+n+1); if(m>n*n)tepan();
for(rg i=1;i<=n;++i) S[i]=S[i-1]+a[i].da;
for(rg i=1;i<=m;++i) f[0][i]=1e9;
for(rg i=1;i<=n;++i){
for(rg j=0;j<=m;++j){
if(j<i){f[i][j]=1e9; continue;}
f[i][j]=f[i][j-i]; d[i][j].x=i; d[i][j].y=j-i;
for(rg k=0;k<i;++k){
rg tot=f[k][j-(i-k)]+k*(S[i]-S[k]);
if(tot<f[i][j])f[i][j]=tot,d[i][j].x=k,d[i][j].y=j-(i-k);
}
}
} printf("%d\n",f[n][m]); print(n,m);
for(rg i=1;i<=n;++i) printf("%d ",as[i]);
puts(""); return 0;
}

CH 5105 Cookies(贪心+DP)的更多相关文章

  1. 【CH5105】cookies 贪心+DP

    通过邻项交换法可知,怨气值大的孩子分得的饼干数也应该多(否则交换之后得到的解更优). 观察目标函数的性质,可知目标函数本身是由孩子饼干数的相对大小得到,因此此题中关注的是相对大小. 状态设计:\(dp ...

  2. 【BZOJ-3174】拯救小矮人 贪心 + DP

    3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 686  Solved: 357[Submit][Status ...

  3. 洛谷P4823 拯救小矮人 [TJOI2013] 贪心+dp

    正解:贪心+dp 解题报告: 传送门! 我以前好像碰到过这题的说,,,有可能是做过类似的题qwq? 首先考虑这种显然是dp?就f[i][j]:决策到了地i个人,跑了j个的最大高度,不断更新j的上限就得 ...

  4. 贪心+DP【洛谷P4823】 [TJOI2013]拯救小矮人

    P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...

  5. BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP

    BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...

  6. 【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp

    题目描述 给出 $A$ 串和 $B$ 串,从 $A$ 串中选出至多 $x$ 个互不重合的段,使得它们按照原顺序拼接后能够得到 $B$ 串.求是否可行.多组数据. $T\le 10$ ,$|A|,|B| ...

  7. 【bzoj3174】[Tjoi2013]拯救小矮人 贪心+dp

    题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人,我们知道他从脚 ...

  8. hdu 1257 最少拦截系统【贪心 || DP——LIS】

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1257 http://acm.hust.edu.cn/vjudge/contest/view.action ...

  9. 贪心+dp

    贪心+dp 好多题都是这个思想, 可以说是非常重要了 思想一: 在不确定序列无法dp的情况下, 我们不妨先假设序列已经选定, 而利用贪心使序列达到最优解, 从而先进行贪心排序, 在进行dp选出序列 思 ...

随机推荐

  1. Unity3D for iOS初级教程:Part 3/3

    转自Unity 3D for iOS 这篇文章还可以在这里找到 英语 Learn how to use Unity to make a simple 3D iOS game! 这份教程是由教程团队成员 ...

  2. [luoguP2606] [ZJOI2010]排列计数(DP)

    传送门 如果能够根据题意看出这是一个堆的话,那么就有些思路了.. 首先堆顶必须是最小元素,然后左右儿子可以预处理出来都有多少个数, 把剩余的数任意分配给两个儿子,用排列组合即可 dp(now) = d ...

  3. BZOJ 1015: [JSOI2008]星球大战starwar【并查集】

    题目可以表述成:给定一个无向图G,每次删除它的一个点和与点相关的边集,每次询问该操作后图G的连通度(连通分量的个数).和上一题一样都是考察逆向思维,虽然删除点的做法不会,但是每次加点后询问连通度却是并 ...

  4. [HNOI2010]CHORUS 合唱队 (区间DP)

    题目描述 对于一个包含 NN 个整数的数列 AA ,我们可以把它的所有元素加入一个双头队列 BB . 首先 A1A1 作为队列的唯一元素,然后依次加入 A2∼ANA2∼AN ,如果 Ai<Ai− ...

  5. 用 Jackson 来处理 JSON

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好. 首先创建一个User对象类 (User.java) package com.sivalabs.json; impor ...

  6. Laravel 静态资源管理

    <link rel="stylesheet" href="{{ asset('bootstrap/css/bootstrap.min.css') }}" ...

  7. PSO(Thepopularity-similarity-oplimization) modol

    PSO(Thepopularity-similarity-oplimization) modol 在这篇文章里,我们试图将社交关系构成的网络结构从纷繁复杂的具体场景.细节条件中剥离出来,单单从个体间连 ...

  8. LightOJ1234 Harmonic Number 调和级数求和

    [题目] [预备知识] ,其中r是欧拉常数,const double r= 0.57721566490153286060651209; 这个等式在n很大 的时候 比较精确. [解法]可以在 n较小的时 ...

  9. haproxy和nginx负载均衡分析

    https://my.oschina.net/zhuangweihong/blog/813231

  10. error MIDL2311 解决方法

    error MIDL2311 : statements outside library block are illegal in mktyplib compatability mode : [] 在编 ...