一本通提高篇——斜率优化DP

斜率优化DP:DP的一种优化形式,主要用于优化如下形式的DP

f[i]=f[j]+x[i]*x[j]+...

学习可以参考下面的博客:

https://www.cnblogs.com/Xing-Ling/p/11210179.html

https://blog.csdn.net/xiang_6/article/details/81450647

我的做法结合了这两种方案。

首先,用代数法求出进行状态更新的条件。

然后,判断上凸还是下凸。

在下一步,求出斜率,用于把起始且并不优的状态淘汰。

最后,就可以写代码了

主要题目:

loj10188装箱游戏

 1 #include<bits/stdc++.h>
 2 #define rll register long long
 3 using namespace std;
 4 const int maxn=5e7+10;
 5 typedef long long ll;
 6 ll sum[maxn],f[maxn],q[maxn];
 7 ll n,l,h=1,t=0;
 8 
 9 inline ll min(rll a,rll b){return a<b?a:b;}
10 inline ll X(rll i){return sum[i]+i;}
11 inline ll Y(rll i){return f[i]+(sum[i]+i+1+l)*(sum[i]+i+1+l);}
12 inline long double xl(rll a,rll b){return (long double)(Y(b)-Y(a))/(X(b)-X(a));}
13 
14 int main()
15 {
16     scanf("%lld%lld",&n,&l);
17     for(ll i=1;i<=n;++i)
18     {
19         scanf("%lld",sum+i);
20         sum[i]+=sum[i-1];
21     }
22     q[++t]=0;
23     for(ll i=1;i<=n;++i)
24     {
25         while(h<t && xl(q[h],q[h+1])<=2*(sum[i]+i))++h;
26         int j=q[h];
27         f[i]=f[j]+(sum[i]-sum[j]+i-j-1-l)*(sum[i]-sum[j]+i-j-1-l);
28         while(h<t && xl(q[t],i)<=xl(q[t-1],q[t]))t--;
29         q[++t]=i;
30     }
31     cout<<f[n];
32     return 0;
33 }
View Code

loj10189仓库建设

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6 + 10;
 5 ll n;
 6 ll x[maxn], sum[maxn], s[maxn], c[maxn], f[maxn];
 7 ll tail, head, q[maxn];
 8 inline ll X(ll a) { return sum[a]; }
 9 inline ll Y(ll a) { return f[a] + s[a]; }
10 inline long double xl(ll a, ll b) { return (long double)(Y(b) - Y(a)) / (X(b) - X(a)); }
11 
12 int main() {
13     scanf("%lld", &n);
14     for (ll p, i = 1; i <= n; ++i) {
15         scanf("%lld%lld%lld", x + i, &p, c + i);
16         sum[i] = sum[i - 1] + p;
17         s[i] = s[i - 1] + p * x[i];
18     }
19     tail = 0, head = 1;
20     q[++tail] = 0;
21     for (ll i = 1; i <= n; ++i) {
22         while (tail > head && xl(q[head], q[head + 1]) <= x[i]) ++head;
23         int j = q[head];
24         f[i] = f[j] + x[i] * (sum[i] - sum[j]) - s[i] + s[j] + c[i];
25         while (tail > head && xl(q[tail], i) <= xl(q[tail - 1], q[tail])) --tail;
26         q[++tail] = i;
27     }
28     cout << f[n];
29     return 0;
30 }
View Code

loj10190特别行动队

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e6 + 10;
 4 typedef long long ll;
 5 ll q[maxn], h = 1, t = 0;
 6 ll n, a, b, c, s[maxn], f[maxn];
 7 inline ll X(ll i) { return s[i]; }
 8 inline ll Y(ll i) { return f[i] + a * s[i] * s[i] - b * s[i]; }
 9 inline long double xl(ll a, ll b) { return (long double)(Y(b) - Y(a)) / (X(b) - X(a)); }
10 int main() {
11     scanf("%lld%lld%lld%lld", &n, &a, &b, &c);
12     for (int i = 1; i <= n; ++i) {
13         scanf("%lld", s + i);
14         s[i] += s[i - 1];
15     }
16     q[++t] = 0;
17     for (int i = 1; i <= n; ++i) {
18         while (t > h && xl(q[h], q[h + 1]) >= 2 * a * s[i]) ++h;
19         int j = q[h];
20         f[i] = f[j] + a * (s[i] - s[j]) * (s[i] - s[j]) + b * (s[i] - s[j]) + c;
21         while (t > h && xl(q[t - 1], q[t]) <= xl(q[t], i)) --t;
22         q[++t] = i;
23     }
24     cout << f[n];
25     return 0;
26 }
View Code

loj10191打印文章

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 5e5 + 10;
 5 ll n, m;
 6 ll s[maxn], f[maxn];
 7 ll h, t, q[maxn];
 8 inline ll X(ll i) { return s[i]; }
 9 inline ll Y(ll i) { return f[i] + s[i] * s[i]; }
10 // inline long double xl(ll a,ll b){return (long double)(Y(b)-Y(a))/(X(b)-X(a));}
11 int main() {
12     while (scanf("%lld%lld", &n, &m) == 2) {
13         memset(s, 0, sizeof s);
14         memset(f, 0, sizeof f);
15         memset(q, 0, sizeof q);
16         h = 1, t = 0;
17         for (int i = 1; i <= n; ++i) {
18             scanf("%lld", s + i);
19             s[i] += s[i - 1];
20         }
21         q[++t] = 0;
22         for (int i = 1; i <= n; ++i) {
23             while (h < t && Y(q[h + 1]) - Y(q[h]) <= 2 * s[i] * (X(q[h + 1]) - X(q[h]))) ++h;
24             ll j = q[h];
25             f[i] = f[j] + (s[i] - s[j]) * (s[i] - s[j]) + m;
26             while (h < t &&
27                    (Y(q[t]) - Y(q[t - 1])) * (X(i) - X(q[t])) >= (Y(i) - Y(q[t])) * (X(q[t]) - X(q[t - 1])))
28                 --t;
29             q[++t] = i;
30         }
31         printf("%lld
", f[n]);
32     }
33     return 0;
34 }
View Code

loj10192锯木厂选址

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e5 + 10;
 4 typedef long long ll;
 5 ll n, dis[maxn], w[maxn], sw[maxn], swd[maxn], f[maxn][2];
 6 ll h = 1, t, q[maxn];
 7 
 8 inline ll x(ll i) { return sw[i]; }
 9 inline ll y(ll i) { return f[i][0] + swd[i]; }
10 
11 int main() {
12     scanf("%lld", &n);
13     for (ll d, i = 1; i <= n; ++i) {
14         scanf("%lld%lld", w + i, &d);
15         dis[i + 1] = dis[i] + d;
16         sw[i] = sw[i - 1] + w[i];
17         swd[i] = swd[i - 1] + w[i] * dis[i];
18     }
19     sw[n + 1] = sw[n];
20     swd[n + 1] = swd[n];
21     for (ll i = 2; i <= n; ++i) f[i][0] = dis[i] * sw[i] - swd[i];
22     q[++t] = 1;
23     for (ll i = 2; i <= n; ++i) {
24         while (h < t && y(q[h + 1]) - y(q[h]) <= dis[i] * (x(q[h + 1]) - x(q[h]))) ++h;
25         ll j = q[h];
26         f[i][1] = f[j][0] + dis[i] * (sw[i] - sw[j]) - (swd[i] - swd[j]);
27         while (h < t &&
28                (y(q[t]) - y(q[t - 1])) * (x(i) - x(q[t])) >= (y(i) - y(q[t])) * (x(q[t]) - x(q[t - 1])))
29             --t;
30         q[++t] = i;
31     }
32     ll ans = (ll)1 * 100000000 * 100000000;
33     for (int i = 1; i <= n; ++i)
34         if (ans > f[i][1] + dis[n + 1] * (sw[n + 1] - sw[i]) - (swd[n + 1] - swd[i]))
35             ans = f[i][1] + dis[n + 1] * (sw[n + 1] - sw[i]) - (swd[n + 1] - swd[i]);
36     cout << ans;
37 
38     return 0;
39 }
View Code

loj10184任务安排1

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 5e3 + 10;
 5 ll n, s;
 6 ll f[maxn], sc[maxn], st[maxn];
 7 
 8 int main() {
 9     scanf("%lld%lld", &n, &s);
10     for (int i = 1; i <= n; ++i) {
11         scanf("%lld%lld", st + i, sc + i);
12         st[i] += st[i - 1];
13         sc[i] += sc[i - 1];
14     }
15     for (int i = n; i > 0; --i) {
16         f[i] = (st[n] + s) * (sc[n] - sc[i - 1]);
17         for (int j = i + 1; j <= n; ++j) {
18             if (f[i] > f[j] + st[j - 1] * (sc[j - 1] - sc[i - 1]) + (sc[n] - sc[i - 1]) * s)
19                 f[i] = f[j] + st[j - 1] * (sc[j - 1] - sc[i - 1]) + (sc[n] - sc[i - 1]) * s;
20         }
21     }
22     cout << f[1];
23     return 0;
24 }
View Code

loj10185任务安排2

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=1e4+10;
 5 int n,s;
 6 int f[maxn],sc[maxn],smt[maxn];
 7 int q[maxn],l,r;
 8 ll y(int a)
 9 {
10     return f[a]+sc[a]*smt[a];
11 }
12 long double get_xl(int a,int b)
13 {
14     return (long double)(y(b)-y(a))/(smt[b]-smt[a]);
15 }
16 int main()
17 {
18     scanf("%d%d",&n,&s);
19     for(int t,c,i=1;i<=n;++i)
20     {
21         scanf("%d%d",&smt[i],&sc[i]);
22         smt[i]+=smt[i-1];
23         sc[i]+=sc[i-1];
24     }
25     for(int i=n;i>=0;--i)
26     {
27         while(l<r&&get_xl(q[l],q[l+1])>=sc[i])++l;
28         f[i]=f[q[l]]+(sc[q[l]]-sc[i])*smt[q[l]]+(sc[n]-sc[i])*s;
29         while(l<r&&get_xl(q[r-1],q[r])<=get_xl(q[r],i))--r;
30         q[++r]=i;
31     }
32     cout<<f[0]<<endl;
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/gryzy/p/13129240.html