斜率优化 学习笔记
斜率优化 学习笔记
https://www.cnblogs.com/Xing-Ling/p/11210179.html
总结:
移项将 Dp 方程化为 \(y=kx+b\) 的形式,其中,\(x,\ y\) 仅与 \(j\) 有关,\(k,\ b\) 仅与 \(i\) 有关。
\(y(dp[j]+A)=k(?_i)x(B\times ?_j)+b(dp[i]+C)\) 的形式。
https://oi-wiki.org/dp/opt/slope/#%E4%BE%8B%E9%A2%98%E5%BC%95%E5%85%A5
考虑一次函数的斜截式 \(y=kx+b\),将其移项得到 \(b=y-kx\)。我们将与 \(j\) 有关的信息表示为 \(y\) 的形式,把同时与 \(i,j\) 有关的信息表示为 \(kx\),把要最小化的信息(与 \(i\) 有关的信息)表示为 \(b\),也就是截距。具体地,设
则转移方程就写作 \(b_i = \min_{j<i}\{ y_j-k_ix_j \}\)。我们把 \((x_j,y_j)\) 看作二维平面上的点,则 \(k_i\) 表示直线斜率,\(b_i\) 表示一条过 \((x_j,y_j)\) 的斜率为 \(k_i\) 的直线的截距。问题转化为了,选择合适的 \(j(1\le j<i)\),最小化直线的截距。
\(\Large{\text{ R. 任务安排4.1}}\)
题解:https://www.cnblogs.com/Wy-x/articles/18969298
$\large{\color{purple}点击查看 R. 任务安排4.1 代码}$
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,s;
int t[1<<20],f[1<<20];
int dp[1<<20];
struct Node{
int x,y,id;
};
vector<Node> v;
#define X(i) (f[i])
#define Y(i) (dp[i])
#define K(i) (t[i])
int find(const Node x)
{
int l=0,r=v.size()-1;
while(l<r)
{
int mid=(l+r)>>1;
if(v[mid].x<x.x) l=mid+1;
else r=mid-1;
}
l-=5;
r+=5;
if(l<0) l=0;
if(r>=v.size()) r=v.size()-1;
for(int i=r;i>=l;i--)
if(v[i].x<=x.x) return i+1;
return 0;
}
signed main()
{
n=read();
s=read();
for(int i=1;i<=n;i++)
{
int ti=read(),fi=read();
t[i]=t[i-1]+ti;
f[i]=f[i-1]+fi;
}
memset(dp,0x3f,sizeof(dp));
dp[0]=s*f[n];
v.push_back({X(0),Y(0),0});
for(int i=1;i<=n;i++)
{
while(v.size()>1&&(v[1].y-v[0].y)<=K(i)*(v[1].x-v[0].x)) v.erase(v.begin());
int p=v[0].id;
dp[i]=dp[p]+(f[i]-f[p])*t[i]+s*(f[n]-f[i]);
dp[i]=min(dp[i],dp[0]+(f[i]-f[0])*t[i]+s*(f[n]-f[i]));
Node nw={X(i),Y(i),i};
p=find(nw);
v.insert(v.begin()+p,nw);
if(p>0&&p<v.size()-1)
{
if((v[p+1].y-v[p].y)*(v[p].x-v[p-1].x)<=(v[p].y-v[p-1].y)*(v[p+1].x-v[p].x))
{
v.erase(v.begin()+p);
continue;
}
}
while(p>1&&(v[p].y-v[p-1].y)*(v[p-1].x-v[p-2].x)<=(v[p-1].y-v[p-2].y)*(v[p].x-v[p-1].x))
{
v.erase(v.begin()+p-1);
p--;
}
while(p<v.size()-2&&(v[p+2].y-v[p+1].y)*(v[p+1].x-v[p].x)<=(v[p+1].y-v[p].y)*(v[p+2].x-v[p+1].x))
{
v.erase(v.begin()+p+1);
p++;
}
// while()
// for(int j=0;j<i;j++)
// dp[i]=min(dp[i],dp[j]+(f[i]-f[j])*t[i]+s*(f[n]-f[i]));
}
cout<<dp[n];
return 0;
}
DP 优化 解题报告
直接线下找我,不想写了。😃
A. [NOIP2012 提高组] 开车旅行
咕。
B. 计算重复Count The Repetitions
咕。
C. Cleaning Shifts清理班次1
D. Cleaning Shifts清理班次2
E. 赤壁之战The Battle of Chibi
F. 围栏Fence
G. 裁剪序列Cut the Sequence
H. 「一本通 5.5 例 2」最大连续和
I. [Scoi2010]股票交易
J. 瑰丽华尔兹
K. [USACO Open11] 修剪草坪
L. [Usaco2013 Nov]Pogo-Cow
M. [tyvj1305]最大子序和
N. [SCOI2009] 生日礼物
O. 任务安排1
以下是博客签名,正文无关
本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/p/18801240
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC-BY-NC-SA 4.0 协议)进行许可。

浙公网安备 33010602011771号