http://contest-hunter.org:83/contest/0x50%E3%80%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E3%80%8D%E4%BE%8B%E9%A2%98/5105%20Cookies


大概有一个初步状态的设计想法,第一维dp到第几个人,第二位dp发了多少饼干。但是人是杂乱无章的,无法进行dp。尝试将无序化为有序,看看可不可以排序。

发现越贪婪的人,我们希望他拿的饼干越多,因为少的话造成的代价大嘛,所以宁愿让贪婪度小的人去造成代价。

猜到最优方案一定是按贪婪度从大到小排序后从左到右分发饼干单调不增的。可以用微扰证明,比如假设在排序后的某个人之后的人分的饼干比这人多,发现剩下的人不会消去怨气可能会更多。对于两个人来说,通过自身贪婪度关系可以比较出这样一定是不优的。日常口胡证明毕。

所以有了顺序,$g$从大到小,dp。暴力思路是$f[i][j][k]$表示第$i$个人时发了$j$个,本人拿了$k$个的min代价。所以每次枚举$i,j,k$,再考虑和之前的大小关系,也就是枚举之前连续多少个人和他拿的饼干一样多,然后转移。

$f[i][j][k]=min\{f[i-l][j-l*k][p]+sum[i-l+1$~$i]*(i-l)\}$

然后会享受到时空双炸。然后就卡住了。。。。

lyd给的做法乍一看有点神仙。。根本想不到啊。。。但是仔细剖析一下,其本质就是对上面暴力的一种(等效)优化。优化功夫还不到家啊。。

发现原本枚举第$i$个人拿了$k$个饼干并向前枚举有多少人也拿了$k$个,这样其实是没有必要的多余计算。当第$i$个人取了$1$个饼干,向前直接枚举即可。

而假设要计算取了$k(k \geqslant 2)$个饼干的话呢,这种情况可以直接由之前推过的状态等效转移。所有人统一去掉$1$块饼干,是不是我之前推过的状态$(f[i][j-i][...])$?也就是说我之前的$j-i$块饼干分配的最优情况,再经过每人都发一块,其最优性不变,也就是$i$取了$k$个的时候的最优情况。(可以反证证明为什么之前的最优的统一加一块就是现在最优的)这等效于我暴力枚举$k$,再枚举人数。其本质是一种前缀min的不断继承

所以状态得到简化 $f[i][j]$表示第$i$个人时发了$j$个的$min$代价。然后每次每个人由选$1$个(暴力dp)和选若干个(等效转移)中取min即可。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+,M=+;const ll INF=1ll<<;
ll f[N][M],sum[N][N];
int ans[N],n,m,cnt;
struct thxorz{
int g,pos;
}A[N];
pii h[N][M];
inline char cmp(thxorz a,thxorz b){return a.g>b.g;} int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
read(n),read(m);
for(register int i=;i<=n;++i)read(A[i].g),A[i].pos=i;
sort(A+,A+n+,cmp);
for(register int i=;i<=n;++i)sum[][i]=sum[][i-]+A[i].g;
for(register int i=;i<=n;++i)for(register int j=;j<=i;++j)sum[j][i]=sum[][i]-sum[][j-];
for(register int i=;i<=n;++i){
for(register int j=;j<i;++j)f[i][j]=INF;f[i][i]=;
for(register int j=i+;j<=m;++j){
f[i][j]=f[i][j-i];h[i][j]=make_pair(i,j-i);
for(register int k=i-;k;--k)if(MIN(f[i][j],sum[k+][i]*k+f[k][j-(i-k)]))h[i][j]=make_pair(k,j-i+k);
}
}
printf("%lld\n",f[n][m]);int x=n;
while(x){
if(h[x][m].first==x)++cnt;
else for(register int i=h[x][m].first+;i<=x;++i)ans[A[i].pos]=cnt+;
pii tmp=h[x][m];x=tmp.first,m=tmp.second;
}
for(register int i=;i<=n;++i)printf("%d ",ans[i]);
return ;
}

CH5105 Cookies[线性DP]的更多相关文章

  1. $CH5105\ Cookies$ 线性$DP+$贪心

    CH 是很有趣的一道题 : ) Sol 第一反应就是f[i][j]表示前i个小朋友分j块饼干的最小怨气值 但是一个孩子所产生的怨气值并不固定,它与其他孩子获得饼干的情况有关 这里可以用到一个贪心,就是 ...

  2. LightOJ1044 Palindrome Partitioning(区间DP+线性DP)

    问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...

  3. Codeforces 176B (线性DP+字符串)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...

  4. hdu1712 线性dp

    //Accepted 400 KB 109 ms //dp线性 //dp[i][j]=max(dp[i-1][k]+a[i][j-k]) //在前i门课上花j天得到的最大分数,等于max(在前i-1门 ...

  5. 动态规划——线性dp

    我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...

  6. POJ 2479-Maximum sum(线性dp)

    Maximum sum Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 33918   Accepted: 10504 Des ...

  7. poj 1050 To the Max(线性dp)

    题目链接:http://poj.org/problem?id=1050 思路分析: 该题目为经典的最大子矩阵和问题,属于线性dp问题:最大子矩阵为最大连续子段和的推广情况,最大连续子段和为一维问题,而 ...

  8. nyoj44 子串和 线性DP

    线性DP经典题. dp[i]表示以i为结尾最大连续和,状态转移方程dp[i] = max (a[i] , dp[i - 1] + a[i]) AC代码: #include<cstdio> ...

  9. 『最大M子段和 线性DP』

    最大M子段和(51nod 1052) Description N个整数组成的序列a[1],a[2],a[3],-,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M &g ...

随机推荐

  1. CornerNet-Lite算法笔记

    论文名称:CornerNet-Lite: Efficient Keypoint Based Object Detection 论文链接:https://arxiv.org/abs/1904.08900 ...

  2. elasticsearch的cross_fields查询

    1.most_fields 这种方式搜索也存在某些问题 它不能使用 operator 或 minimum_should_match 参数来降低次相关结果造成的长尾效应. 2.词 peter 和 smi ...

  3. 我理解的CLH

    学而时习之,不亦说乎!                              --<论语> 原创,转载请附原文链接,谢谢. CLH 思路 保持时序的锁基本思路就是将等待获取锁的线程放入 ...

  4. 浏览器渲染优化4(styles and layout)

    你已经学会了查找和解决问题.希望你的js能正常运行了,但这只是制作帧的一小部分.在这节课里,你将处理样式,也就是像开发工具里标记的那样,重新计算样式.学完这节课后,你将学会从样式计算过程中找到性能问题 ...

  5. typescript中新增的基本数据类型

    javascript中有7种数据类型,分别是:boolean,number,string,null,undefined和object,以及在es6中新增的一种类型 symbol.而typescript ...

  6. (二)Java秒杀项目之实现登录功能

    一.数据库设计 CREATE TABLE `miaosha_user` ( `id` ) NOT NULL COMMENT '用户ID,手机号码', `nickname` ) NOT NULL, `p ...

  7. APP_测试流程(测试点)

    1 APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间. 1.3测试资 ...

  8. position详解

    本文旨在普及一下position的用法,CSS中position的使用率相当之高,对于新入行的小白,不仅要知其然,还要知其所以然. position(定位类型),主要有4种属性值 : static.f ...

  9. Maven将java打包成jar并且运行笔记

    Maven项目打包成jar并且运行笔记 首先创建一个maven项目 运行成功后,有两种方式将项目进行打包. 第一种方式: 在IDEA编辑器中maven项目进行打包: 这里显示jar包中没有主清单属性, ...

  10. springboot(二十二)-sharding-jdbc-读写分离

    前面我们使用sharding-jdbc配置了分库分表.sharding-jdbc还有个用法,就是实现读写分离. 什么时候需要或者可以使用读写分离? 当我们的项目所使用的数据库查询的访问量,访问频率,及 ...