对于刷题量我觉得肯定是刷的越多越好(当然这是对时间有很多的人来说。

但是在我看来我的确适合刷题较多的那一类人,应为我对知识的应用能力并不强。这两天学习的内容是dp的斜率优化。当然我是不太会的。

这个博文肯定也是不断更新的(随着我对斜率优化的不断深入的理解。

这两天做的题是一道经典的任务安排。

这道题是我两个星期前都想a掉的题。然后都是一个最简单的状态转移方程都推不出,真的是菜到家了。

然后翻书有一个最简单的状态转移方程,看了几分钟发现看的不是很懂而且我感觉这题应该自己思考。

所以扔下来了。两个星期回来再写,发现自己有了思路。

推了一个状态转移方程拿了60分比较骄傲,因为自己的dp很垃圾,现在我觉得才刚入门。

const int MAXN=;
int n,s;
int c[MAXN],t[MAXN];
int f[MAXN][MAXN],ans=INF;
//设f[i][j]表示前i个任务分成j组所能得到的最小值。目标min{f[n][i] i->1~n};
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(int i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=i;j++)
{
for(int k=;k<=i;k++)//枚举这一组选择几项任务
{
f[i][j]=min(f[i][j],f[i-k][j-]+(s*j+t[i])*(c[i]-c[i-k]));
}
}
}
for(int i=;i<=n;i++){ans=min(ans,f[n][i]);}
put(ans);
return ;
}

这是自己打的代码能拿60分欸。复杂度n^3 超级高应为n<=MAXN

水了60心满意足。然后可以心安理得的翻书,书上和我定义的state不太一样。

const int MAXN=;
int n,s;
int c[MAXN],t[MAXN];
int f[MAXN][MAXN],ans=INF;
//设f[i][j]表示前i个任务分成j组所能得到的最小值。目标min{f[n][i] i->1~n};
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(int i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=i;j++)
{
for(int k=;k<i;k++)//枚举上一组选取了多少任务
{
f[i][j]=min(f[i][j],f[k][j-]+(s*j+t[i])*(c[i]-c[k]));
}
}
}
for(int i=;i<=n;i++){ans=min(ans,f[n][i]);}
put(ans);
return ;
}

当然实现起来细节地方写自己的状态转移方程其实都是一样的。重点是状态不一样,值得借鉴。

然后考虑优化则么优化呢?经过书上的短短几行的点播。

它给出了一个其实不用枚举多少组,直接省掉一个for 和一个维度。比较好的思路。

书上说是费用提前计算的经典思想。

const long long MAXN=,INF=21474836474836ll;
long long n,s;
long long c[MAXN],t[MAXN];
long long f[MAXN];
//f[i]表示前i个任务分成过若干批完成执行的最小费用
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
for(long long i=;i<=n;i++)f[i]=INF;
f[]=;
for(long long i=;i<=n;i++)
{
for(long long j=;j<i;j++)
{
f[i]=min(f[i],f[j]+t[i]*(c[i]-c[j])+s*(c[n]-c[j]));
}
}
put(f[n]);
return ;
}

这样的话就可以实现了分成多少组和当前这一组选多少个物品的结合。

这样的话很显然是比较优秀的做法。骤降一个维度和一个维度的时间。这种思想不错!

关键是数据范围还有更大的。n^2的做法也适应不了。

寒假回来 斜率优化大致懂了维护凸包什么的是关键所以代码中有解释自己打的哦!

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 168430090000ll
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?putchar('-'),x=-x:;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const long long MAXN=;
long long n,s;
long long f[MAXN];//f[i]表示第i个任务完成所需最小费用
long long T[MAXN],F[MAXN],q[MAXN<<],l=,r=;
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)
{
T[i]=read();
F[i]=read();
T[i]+=T[i-];
F[i]+=F[i-];
}
memset(f,,sizeof(f));
f[]=;q[l]=;
for(long long i=;i<=n;i++)//枚举第i个任务
{
long long B=T[i]*F[i]+s*F[n];
long long K=T[i]+s;
while(l<r&&((f[q[l+]]-f[q[l]])<=K*(F[q[l+]]-F[q[l]])))l++;
f[i]=f[q[l]]-K*F[q[l]]+B;
while(l<r&&(f[q[r]]-f[q[r-]])*(F[i]-F[q[r]])>=(f[i]-f[q[r]])*(F[q[r]]-F[q[r-]]))r--;
//注意 除法变成乘法 大于等于号方向别搞反
q[++r]=i;
/*for(long long j=0;j<i;j++)//枚举前面的那个任务
{
//f[i]=min(f[i],f[j]+T[i]*(F[i]-F[j])+s*(F[n]-F[j]));
//f[i]=min(f[i],f[j]-T[i]*F[j]+T[i]*F[i]+s*F[n]-s*F[j]);
ans=min(ans,f[j]-K*F[j]);
//K显然是斜率 每一个f[i]的求出都是以F[j]为变量对应一个f[j]
//显然当斜率......想通就可以
f[i]=ans+B;f[i]=f[j]-K*F[j]+B;
f[j]=f[i]-B+k*f[j];显然这是一个点斜式
//截距为f[i]-B;截距越小f[i]越小
}*/
}
put(f[n]);
return ;
}

然后我们会发现一个东西就是我不断出队队首的原因 也就是寻找一个点 (设点a,b,c,此时斜率为k,k>kab,k<kac)b这个点就是最优转移决策。

这个东西是一定的呢!蒟蒻不会证明但是会画图 把所有情况画出来 发现了或者是“显然”的发现了这一特异性的结论。

例题:

这里的T 有可能是负数,那么我们的斜率T[i]+s就不再具有单调性如果像上述方法直接把队首出队的话那么当前斜率可能依赖之前队首的点

所以这里我们要维护整个下凸的凸包然后每次通过在这个凸包上二分来寻找最优决策。

二分不好写 RE WA 很难调但是坚持 就能调对。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 168430090
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?putchar('-'),x=-x:;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
//任务安排升级版 T可能为负值 RE:应将除法变成乘法小心0
const long long MAXN=;
long long n,s;
long long T[MAXN],F[MAXN];
long long f[MAXN];//f[i]表示第i个任务完成所需最小时间
long long q[MAXN],h,t;
int g[MAXN],l,r;
long long find(long long x)
{
if(h==t)return h;
long long l=h,r=t;
while(l+<r)
{
long long mid=(l+r)>>;
int tmp1=(F[q[mid]]-F[q[mid-]]);
int tmp2=(F[q[mid+]]-F[q[mid]]);
long long K1=((f[q[mid]]-f[q[mid-]]));
long long K2=((f[q[mid+]]-f[q[mid]]));
if(K1<x*tmp1&&K2>x*tmp2)return mid;
if(K1<x*tmp1&&K2<x*tmp2)l=mid;
else r=mid;
}
int tmp=(F[q[r]]-F[q[l]]);
long long K3=((f[q[r]]-f[q[l]]));
if(K3<x*tmp)return r;
if(K3>x*tmp)return l;
return r;
}
int main()
{
freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)
{
T[i]=read();
T[i]+=T[i-];
F[i]=read();
F[i]+=F[i-];
}
for(long long i=;i<=n;i++)
{
long long K=T[i]+s;
long long B=F[i]*T[i]+s*F[n];
long long tmp=find(K);
//cout<<tmp<<endl;
f[i]=f[q[tmp]]-F[q[tmp]]*K+B;
while(h<t&&((f[q[t]]-f[q[t-]])*(F[i]-F[q[t]]))>=((f[i]-f[q[t]])*(F[q[t]]-F[q[t-]])))t--;
q[++t]=i;
}
put(f[n]);
return ;
}

要走的路还长。

dp的斜率优化的更多相关文章

  1. 【DP】斜率优化

    斜率优化 入门题:PKU3709 很多人貌似都是做这道题来K斜率优化的,所以看了资料以后还是开始入手吧. 然而还是得跪求大神的程序啊 ORZ ORZ…… 其实理解斜率优化就是会列斜率不等式,还要理解剔 ...

  2. bzoj 1010 [HNOI2008]玩具装箱toy(DP的斜率优化)

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7874  Solved: 3047[Submit][St ...

  3. 洛谷P3195 [HNOI2008] 玩具装箱 [DP,斜率优化,单调队列优化]

    题目传送门 题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N ...

  4. 【HDOJ5956】The Elder(树形DP,斜率优化)

    题意:有一棵n个点的有根树,每条边上有一个边权.给定P,从i跳到它的祖先j的费用是距离的平方+P,问所有点中到根节点1的总花费最大值 n<=1e5,p<=1e6,w<=1e2 思路: ...

  5. CF1179D Fedor Runs for President [DP,斜率优化]

    Codeforces 思路 考虑把连的那两个点中间的链提出来,那么就会变成一条链,链上的每个点挂着一棵子树的形式. 设那些子树的大小为\(S_1,S2,\cdots\),那么新加的简单路径个数就是 \ ...

  6. dp之斜率优化

    前几天想练练思维,所以从cf上随便找了一道dp题,看完题意后第一感觉很简单,就是简单的区间dp题,但是看到数据范围的我顿时就懵了,(1≤n≤105) emmmmmmmm,按照普通的思路肯定会超时的.. ...

  7. 【DP】斜率优化初步

    向y总学习了斜率优化,写下这篇blog加深一下理解. 模板题:https://www.acwing.com/problem/content/303/ 分析 因为本篇的重点在于斜率优化,故在此给出状态转 ...

  8. [bzoj1492][NOI2007]Cash[CDQ分治;dp;斜率优化]

    首先,设f[x]表示x天能获得的A券最大值,有动规方程: $f[i]=max\{f[j]*A[i]+f[j]*B[i]/R[j]\}*R[i]/(R[i]*A[i]+B[i])$, 设 $j<k ...

  9. CF932F Escape Through Leaf(DP,斜率优化)

    SB 题. 写出 DP 方程:\(f_i\) 表示从 \(i\) 跳的最小值. \(i\) 是叶子就是 \(0\),否则就是选个子树中的 \(v\),\(f_i=\min(f_v+a_ib_v)\). ...

随机推荐

  1. 省市区三级联动——思路、demo、示例

    说明(2017-12-13 11:03:58): 1. 这个功能应该是注册的时候非常.常用的了,不过现在都是微信登录,手机端自动获取位置什么的,可能就网站还用用吧! 2. 这个东西的难点在于统计各地省 ...

  2. MXNET:卷积神经网络基础

    卷积神经网络(convolutional neural network).它是近年来深度学习能在计算机视觉中取得巨大成果的基石,它也逐渐在被其他诸如自然语言处理.推荐系统和语音识别等领域广泛使用. 目 ...

  3. [数据]matplotlib总结

    这里权当一个matplotlib的用法小结,主要用于记录,以防忘记. 需要安装一下Anaconda,这里推荐清华大学的镜像:https://mirrors.tuna.tsinghua.edu.cn/h ...

  4. Java 继承中构造方法的执行顺序问题

    在Java中,如果一个类没有任何显式创建的构造器则该类默认会有一个无参构造器:如果显式创建了有参构造器则该类就不再有默认无参构造器. 在Java继承中,构造器并不能被继承,而是被显示或隐式调用. 1. ...

  5. Golang Gin 框架 Route备注

    https://www.jianshu.com/p/d4b52187d233 https://blog.csdn.net/weixin_34210740/article/details/8602756 ...

  6. [Localization] R-CNN series for Localization and Detection

    CS231n Winter 2016: Lecture 8 : Localization and Detection CS231n Winter 2017: Lecture 11: Detection ...

  7. Markdown 表格

    表格的基本写法很简单,就跟表格的形状很相似,冒号在左边表示左对齐,右边表示右对齐,两边都有表示居中,如果都不写冒号则默认左对齐 学号|姓名|分数 :-|:-:|-: 小明|男|75 小红|女|79 小 ...

  8. C#基础--类/接口/成员修饰符,多态、重载、重写,静态和非静态

    C#基础--类/接口/成员修饰符,多态.重载.重写,静态和非静态 类/接口/成员修饰符 C#修饰符---接口: 接口默认访问符是internal接口的成员默认访问修饰符是public C#修饰符--类 ...

  9. 【CF576E】Painting Edges 线段树按时间分治+并查集

    [CF576E]Painting Edges 题意:给你一张n个点,m条边的无向图,每条边是k种颜色中的一种,满足所有颜色相同的边内部形成一个二分图.有q个询问,每次询问给出a,b代表将编号为a的边染 ...

  10. Pyramid Analytics宣布无缝集成BI Office和微软Power BI Desktop

    全球领先的企业商业智能(BI)软件提供商Pyramid Analytics与微软联手,凭借完善的分析平台BI Office强化Power BI Desktop的个人生产力功能.新的“Publish t ...