CH5105 Cookies[线性DP]
大概有一个初步状态的设计想法,第一维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]的更多相关文章
- $CH5105\ Cookies$ 线性$DP+$贪心
CH 是很有趣的一道题 : ) Sol 第一反应就是f[i][j]表示前i个小朋友分j块饼干的最小怨气值 但是一个孩子所产生的怨气值并不固定,它与其他孩子获得饼干的情况有关 这里可以用到一个贪心,就是 ...
- LightOJ1044 Palindrome Partitioning(区间DP+线性DP)
问题问的是最少可以把一个字符串分成几段,使每段都是回文串. 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时 ...
- Codeforces 176B (线性DP+字符串)
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28214 题目大意:源串有如下变形:每次将串切为两半,位置颠倒形成 ...
- 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门 ...
- 动态规划——线性dp
我们在解决一些线性区间上的最优化问题的时候,往往也能够利用到动态规划的思想,这种问题可以叫做线性dp.在这篇文章中,我们将讨论有关线性dp的一些问题. 在有关线性dp问题中,有着几个比较经典而基础的模 ...
- POJ 2479-Maximum sum(线性dp)
Maximum sum Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33918 Accepted: 10504 Des ...
- poj 1050 To the Max(线性dp)
题目链接:http://poj.org/problem?id=1050 思路分析: 该题目为经典的最大子矩阵和问题,属于线性dp问题:最大子矩阵为最大连续子段和的推广情况,最大连续子段和为一维问题,而 ...
- nyoj44 子串和 线性DP
线性DP经典题. dp[i]表示以i为结尾最大连续和,状态转移方程dp[i] = max (a[i] , dp[i - 1] + a[i]) AC代码: #include<cstdio> ...
- 『最大M子段和 线性DP』
最大M子段和(51nod 1052) Description N个整数组成的序列a[1],a[2],a[3],-,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的.如果M &g ...
随机推荐
- C++ vector的详细用法
vector容器类型 vector容器是一个模板类,可以存放任何类型的对象(但必须是同一类对象).vector对象可以在运行时高效地添加元素,并且vector中元素是连续存储的.vector的构造 函 ...
- 用fiddler来学http协议:为什么会有“response body is encoded click to decode”
使用fiddler查看服务器返回的响应包的时候,我们常常会看到“response body is encoded click to decode”这样一个提示,只有点击它才能让响应包的主体内容从乱码变 ...
- 应用安全 - 社工 - 大数据 - Fofa - 汇总
搜索语法 title=”abc” header=”abc” body=”abc” domain=”xx.com” host=”.xx.cn” port=”443” ip=”1.1. ...
- ORACLE 更新 和 插入多条 数据
--插入语句INSERT INTO OA_W_BAOXIAOMXYWB (ID,DONGTAITABLEPARENTSN,CHANPINNAMEGKFK,CHANPINJITIGKFK,CHANPIN ...
- RramSim2
1.官网 http://www.computer.org/csdl/letters/ca/2011/01/lca2011010016-abs.html 2.介绍 http://blog.csdn.ne ...
- 解决Iframe跨域高度自适应,利用window.postMessage()实现跨域消息传递页面高度(JavaScript)
在iframe跨域引用高度自适应这块写的js方式都试了不管用,最终使用的是window.postMessage() 跨域获取高度 传递信息 1.首先,在主页面上使用iframe引入子页面:也就是A.h ...
- 2019牛客暑期多校训练营(第二场)-H Second Large Rectangle(次大子矩阵,降维,直方图+单调栈)
题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目:给n×m的由01组成的矩阵,求次大全1子矩阵的大小. 思路:第一步还是降维操作,用a[i][j]记录 ...
- PTA(Basic Level)1026.程序运行时间
要获得一个 C 语言程序的运行时间,常用的方法是调用头文件 time.h,其中提供了 clock() 函数,可以捕捉从程序开始运行到 clock() 被调用时所耗费的时间.这个时间单位是 clock ...
- 如何在java中去除中文文本的停用词
1. 整体思路 第一步:先将中文文本进行分词,这里使用的HanLP-汉语言处理包进行中文文本分词. 第二步:使用停用词表,去除分好的词中的停用词. 2. 中文文本分词环境配置 使用的HanLP-汉 ...
- 纯前端表格控件SpreadJS以专注业务、提升效率赢得用户与市场
提起华为2012实验室,你可能有点陌生. 但你一定还对前段时间华为的那封<海思总裁致员工的一封信>记忆犹新,就在那篇饱含深情的信中,我们知道了华为为确保公司大部分产品的战略安全和连续供应, ...