斜率优化是单调队列优化的推广

用单调队列维护递增的斜率

参考:https://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

以例1举例说明:

转移方程为:dp[i] = min(dp[j] + (sum[i] - sum[j])^2 + C)

假设k < j < i, 如果从j转移过来比从k转移过来更优

那么 dp[j] + (sum[i] - sum[j])^2 + C < dp[k] + (sum[i] - sum[k])^2 + C

dp[j] - dp[k] < (sum[i] - sum[k])^2 - (sum[i] - sum[j])^2

dp[j] - dp[k] < -2*sum[i]*sum[k] + sum[k]*sum[k] + 2*sum[i]*sum[j] - sum[j]*sum[j]

dp[j] - dp[k] + sum[j]*sum[j] - sum[k]*sum[k] < 2*sum[i]*(sum[j] - sum[k])

(dp[j] - dp[k] + sum[j]*sum[j] - sum[k]*sum[k]) / (sum[j] - sum[k]) < 2*sum[i]

我们观察不等式左边, 它是个斜率的形式, 自变量x为sum, 函数f(x)为dp + sum*sum

我们记这个斜率为g[j, k] = (dp[j] - dp[k] + sum[j]*sum[j] - sum[k]*sum[k]) / (sum[j] - sum[k])

说明1.如果g[j, k] < 2*sum[i] 表示对于dp[i], 从j转移过来比k更优, 反之k更优

说明2.下面我们来考虑着怎么从解集去掉多余的元素, 可以证明可能存在某些元素,无论怎样都不会是最优的,可以去掉这些多余的元素

假设k < j < i

结论:如果g[i, j] < g[j, k], 那么j可以去掉

证明:对于某个i, 如果g[i, j] < 2*sum[i], 那么i比j更优, 结论成立;

                         如果g[i, j] >= 2*sum[i], 那么g[j, k] > g[i, j] >= 2*sum[i], 那么k比j更优,结论成立. 

证毕.

所以如果把所有g[i, j] < g[j, k]的情况中(后面斜率比前面斜率小的情况)的j都去掉, 那么我们就得到相邻两个元素的斜率递增的状况

如下图

下面来说明怎么维护这个解集:

用双端队列维护这个解集, 每次从后面加入元素时, 按照说明2的方式去掉多余元素,使的相邻元素之间构成的斜率保持单调

每次从前面找答案, 由于斜率单调递增, 所以最后一个小于2*sum[i]就是最优的解, 因为这个位置之前的g[i, j]都小于2*sum,

表示后面的比前面更优, 之后的g[i, j] 都大于2*sum, 表示前面的比后面更优, 所以这个点是极值点

又因为sum[i]也具有单调性, 所以下一个极值点的位置肯定大于等于当前极值点, 所以当前极值点之前的都可以从双端队列中移出

ps:所有说明中, k < j < i

例题1:HDU - 3507

思路:维护递增斜率g[i, j] = (dp[i] - dp[j] + sum[i]*sum[i] - sum[j]*sum[j]) / (sum[i] - sum[j])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 5e5 + ;
int a[N], n, m;
LL sum[N], dp[N];
bool g(int k, int j, LL C) {
return (dp[j]-dp[k]+sum[j]*sum[j]-sum[k]*sum[k]) <= C*(sum[j]-sum[k]);
}
bool gg(int k, int j, int i) {
return (dp[i]-dp[j]+sum[i]*sum[i]-sum[j]*sum[j])*(sum[j]-sum[k]) <= (dp[j]-dp[k]+sum[j]*sum[j]-sum[k]*sum[k])*(sum[i]-sum[j]);
}
deque<int> q;
int main() {
while(~scanf("%d %d", &n, &m)) {
for (int i = ; i <= n; ++i) scanf("%d", &a[i]), sum[i] = sum[i-]+a[i];
while(!q.empty()) q.pop_back();
q.push_back();
for (int i = ; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, *sum[i])) ;
else {
q.push_front(a);
break;
}
}
int j = q.front();
dp[i] = dp[j] + (sum[i]-sum[j])*(sum[i]-sum[j])+m;
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(gg(a, b, i)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(i);
}
printf("%lld\n", dp[n]);
}
return ;
}

例题2:HDU - 1300

思路:维护递增斜率g[i, j] = (dp[i] - dp[j]) / (sum[i] - sum[j])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = + ;
int a[N], p[N], n, m, T;
LL sum[N], dp[N];
bool g(int k, int j, LL C) {
return (dp[j]-dp[k]) <= C*(sum[j]-sum[k]);
}
bool gg(int k, int j, int i) {
return (dp[i]-dp[j])*(sum[j]-sum[k]) <= (dp[j]-dp[k])*(sum[i]-sum[j]);
}
deque<int> q;
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for (int i = ; i <= n; ++i) scanf("%d %d", &a[i], &p[i]), sum[i] = sum[i-]+a[i];
for (int i = n-; i >= ; --i) p[i] = min(p[i], p[i+]);
while(!q.empty()) q.pop_back();
q.push_back();
for (int i = ; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, p[i])) ;
else {
q.push_front(a);
break;
}
}
int j = q.front();
dp[i] = dp[j] + (sum[i]-sum[j]+)*p[i];
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(gg(a, b, i)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(i);
}
printf("%lld\n", dp[n]);
}
return ;
}

例题3:HDU - 2993

思路:论文题,维护递增的斜率,居然卡读入,没意思

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 1e5 + ;
int n, k, a[N], q[N], head, tail;
double sum[N];
const int BUF = ;
char Buf[BUF],*buf=Buf;
inline void read(int &a)
{
for(a=;*buf<;buf++);
while(*buf>) a=a*+*buf++-;
}
int main() {
int tot = fread(Buf, , BUF, stdin);
while(true) {
if(buf-Buf+ >= tot) break;
read(n), read(k);
for (int i = ; i <= n; ++i) read(a[i]), sum[i] = sum[i-]+a[i];
head = tail = ;
q[tail++] = ;
double ans = ;
for (int i = k; i <= n; ++i) {
while(head+ < tail) {
int a = q[head];
head++;
int b = q[head];
if((sum[i]-sum[a])*(i-b) < (sum[i]-sum[b])*(i-a)) ;
else {
q[--head] = a;
break;
}
}
int x = q[head];
ans = max(ans, (sum[i]-sum[x])/(i-x));
x = i-k+;
while(head+ < tail) {
int b = q[tail-];
--tail;
int a = q[tail-];
if((sum[x]-sum[b])*(x-a) < (sum[x]-sum[a])*(x-b));
else {
q[tail++] = b;
break;
}
}
q[tail++] = x;
}
printf("%.2f\n", ans);
}
return ;
}

例题4:UVALive - 5097

思路:去重后发现按宽度排序后,高度递减

那么维护递增斜率:g[j, k] = (dp[j] - dp[k]) / (h[k] - h[j])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 5e4 + ;
pii a[N];
vector<pii> vc;
int n, k, h[N], w[N];
LL dp[][N];
deque<int> q[];
bool g(int id, int k, int j, LL C) {
return (dp[id][j]-dp[id][k]) <= C*(h[k+]-h[j+]);
}
bool gg(int id, int k, int j, int i) {
return (dp[id][i]-dp[id][j])*(h[k+]-h[j+]) <= (dp[id][j]-dp[id][k])*(h[j+]-h[i+]);
}
int main() {
while(~scanf("%d %d", &n, &k)) {
for (int i = ; i <= n; ++i) scanf("%d %d", &a[i].fi, &a[i].se);
sort(a+, a++n);
vc.clear();
for (int i = n; i >= ; --i) if(i == n || a[i].se > vc.back().se) vc.pb(a[i]);
reverse(vc.begin(), vc.end());
n = vc.size();
for (int i = ; i < n; ++i) w[i+] = vc[i].fi, h[i+] = vc[i].se;
for (int i = ; i <= k; ++i) while(!q[i].empty()) q[i].pop_back();
q[].push_back();
for (int i = ; i <= k; ++i) for (int j = ; j <= n; ++j) dp[i][j] = 0x3f3f3f3f3f3f3f3f;
dp[][] = ;
for (int i = ; i <= n; ++i) {
for (int j = ; j < k; ++j) {
while(q[j].size() >= ) {
int a = q[j].front();
q[j].pop_front();
int b = q[j].front();
if(g(j, a, b, w[i])) ;
else {
q[j].push_front(a);
break;
}
}
int x = q[j].front();
dp[j+][i] = min(dp[j+][i], dp[j][x] + w[i]*1LL*h[x+]);
while(q[j].size() >= ) {
int b = q[j].back();
q[j].pop_back();
int a = q[j].back();
if(gg(j, a, b, i)) ;
else {
q[j].push_back(b);
break;
}
}
q[j].push_back(i);
}
}
LL ans = 1LL<<;
for (int i = ; i <= k; ++i) ans = min(ans, dp[i][n]);
printf("%lld\n", ans);
}
return ;
}

例题5:HDU - 3045

思路:维护递增斜率:g[j, k] = (dp[j]-dp[k]+sum[k]-sum[j]+a[j+1]*j-a[k+1]*k) / (a[j+1]-a[k+1])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 4e5 + ;
int n, k;
LL a[N], sum[N], dp[N];
bool g(int k, int j, LL C) {
return dp[j]-dp[k]+sum[k]-sum[j]+a[j+]*j-a[k+]*k <= C*(a[j+]-a[k+]);
}
bool gg(int k, int j, int i) {
return (dp[i]-dp[j]+sum[j]-sum[i]+a[i+]*i-a[j+]*j)*(a[j+]-a[k+]) <= (dp[j]-dp[k]+sum[k]-sum[j]+a[j+]*j-a[k+]*k)*(a[i+]-a[j+]);
}
deque<int> q;
int main() {
while(~scanf("%d %d", &n, &k)) {
for (int i = ; i <= n; ++i) scanf("%lld", &a[i]);
sort(a+, a++n);
for (int i = ; i <= n; ++i) sum[i] = sum[i-]+a[i];
while(!q.empty()) q.pop_back();
dp[] = ;
q.push_back();
for (int i = k; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, i)) ;
else {
q.push_front(a);
break;
}
}
int j = q.front();
dp[i] = dp[j]+sum[i]-sum[j]-a[j+]*1LL*(i-j);
if(i-k+ >= k) {
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(gg(a, b, i-k+)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(i-k+);
}
}
printf("%lld\n", dp[n]);
}
return ;
}

例题6:POJ - 1180

思路:要单独算s的影响,因为有s的存在时间就不好算前缀和了,对于每次新的开始s的影响是s*suf[i]

那么就是维护递增斜率:g[j, k] = (dp[j]-dp[k]+s*(suf[j+1]-suf[k+1]) / (sum[j] - sum[k])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<deque>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 1e4 + ;
int T[N], F[N], n, s;
LL sum[N], suf[N], dp[N];
bool g(int k, int j, LL C) {
return dp[j]-dp[k]+s*(suf[j+]-suf[k+]) <= C*(sum[j]-sum[k]);
}
bool gg(int k, int j, int i) {
return (dp[i]-dp[j]+s*(suf[i+]-suf[j+]))*(sum[j]-sum[k]) <= (dp[j]-dp[k]+s*(suf[j+]-suf[k+]))*(sum[i]-sum[j]);
}
deque<int> q;
int main() {
scanf("%d", &n);
scanf("%d", &s);
for (int i = ; i <= n; ++i) scanf("%d %d", &T[i], &F[i]);
for (int i = ; i <= n; ++i) sum[i] = sum[i-] + F[i], T[i]+=T[i-];
for (int i = n; i >= ; --i) suf[i] = suf[i+] + F[i];
q.push_back();
for (int i = ; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, T[i])) ;
else {
q.push_front(a);
break;
}
}
int j = q.front();
dp[i] = dp[j] + T[i]*(sum[i]-sum[j])+s*suf[j+];
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(gg(a, b, i)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(i);
}
printf("%lld\n", dp[n]);
return ;
}

例题7:POJ - 2018

思路:同HDU-2993

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<deque>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 1e5 + ;
int n, f, a[N];
LL sum[N];
deque<int> q;
bool g(int k, int j, int i) {
return (sum[j]-sum[k])*(i-j) <= (sum[i]-sum[j])*(j-k);
}
int main() {
scanf("%d %d", &n, &f);
for (int i = ; i <= n; ++i) scanf("%d", &a[i]), sum[i]=sum[i-]+a[i];
q.push_back();
LL ans = ;
for (int i = f; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, i)) ;
else {
q.push_front(a);
break;
}
}
int x = q.front();
ans = max(ans, (sum[i]-sum[x])*/(i-x));
x = i+-f;
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(!g(a, b, x)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(x);
}
printf("%lld\n", ans);
return ;
}

例题8:POJ - 3709

思路:维护递增斜率:g[j, k] = (dp[j]-dp[k]+sum[k]-sum[j]+a[j+1]*j-a[k+1]*k) / (a[j+1]-a[k+1])

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<deque>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head  const int N = 5e5 + ;
int a[N], n, k, T;
LL sum[N], dp[N];
LL dw(int k, int j) {
return a[j+]-a[k+];
}
LL up(int k, int j) {
return dp[j]-dp[k]+sum[k]-sum[j]+a[j+]*1LL*j-a[k+]*1LL*k;
}
LL g(int k, int j, LL C) {
return up(k, j) <= C*dw(k, j);
}
LL gg(int k, int j, int i) {
return up(j, i)*dw(k, j) <= up(k, j)*dw(j, i);
}
deque<int> q;
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d %d", &n, &k);
for (int i = ; i <= n; ++i) scanf("%d", &a[i]), sum[i]=sum[i-]+a[i];
while(!q.empty()) q.pop_back();
q.push_back();
for (int i = k; i <= n; ++i) {
while(q.size() >= ) {
int a = q.front();
q.pop_front();
int b = q.front();
if(g(a, b, i));
else {
q.push_front(a);
break;
}
}
int x = q.front();
dp[i] = dp[x]+sum[i]-sum[x]-a[x+]*1LL*(i-x);
x = i-k+;
if(x >= k) {
while(q.size() >= ) {
int b = q.back();
q.pop_back();
int a = q.back();
if(gg(a, b, x)) ;
else {
q.push_back(b);
break;
}
}
q.push_back(x);
}
}
printf("%lld\n", dp[n]);
}
return ;
}

例题9:UVA - 12594

思路:维护递增斜率:g[j, k] = (dp[j]-dp[k]+sum[k]-sum[j]-k*s[k]+j*s[j]) / (j-k),其中sum[i] = ∑(j-pos)*pos, s[i] = ∑pos

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define y1 y11
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb emplace_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pli pair<LL, int>
#define pii pair<int, int>
#define piii pair<pii, int>
#define pdd pair<double, double>
#define mem(a, b) memset(a, b, sizeof(a))
#define debug(x) cerr << #x << " = " << x << "\n";
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//head const int N = 2e4 + , M = ;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int T, n, k, pos[];
LL sum[N], s[N], dp[M][N];
char nm[N], pn[N];
deque<int> q[M];
LL up(int id, int k, int j) {
return dp[id][j]-dp[id][k]+sum[k]-sum[j]-k*s[k]+j*s[j];
}
LL dw(int k, int j) {
return j-k;
}
bool g(int id, int k, int j, LL C) {
return up(id, k, j) <= C*dw(k, j);
}
bool gg(int id, int k, int j, int i) {
return up(id, j, i)*dw(k, j) <= up(id, k, j)*dw(j, i);
}
int main() {
scanf("%d", &T);
for(int cs = ; cs <= T; ++cs) {
scanf("%s %d", pn, &k);
scanf("%s", nm+);
n = strlen(nm+);
for (int i = ; i < ; ++i) pos[pn[i]-'a'] = i;
for (int i = ; i <= n; ++i) s[i] = s[i-]+pos[nm[i]-'a'];
for (int i = ; i <= n; ++i) sum[i] = sum[i-]+(i--pos[nm[i]-'a'])*1LL*pos[nm[i]-'a'];
for (int i = ; i <= k; ++i) while(!q[i].empty()) q[i].pop_back();
dp[][] = ;
q[].push_back();
for (int i = ; i <= n; ++i) {
for (int j = ; j < k; ++j) {
while(q[j].size() >= ) {
int a = q[j].front();
q[j].pop_front();
int b = q[j].front();
if(g(j, a, b, s[i])) ;
else {
q[j].push_front(a);
break;
}
}
int x = q[j].front();
dp[j+][i] = dp[j][x]+sum[i]-sum[x]-x*(s[i]-s[x]);
}
for (int j = ; j <= k; ++j) {
while(q[j].size() >= ) {
int b = q[j].back();
q[j].pop_back();
int a = q[j].back();
if(gg(j, a, b, i)) ;
else {
q[j].push_back(b);
break;
}
}
q[j].push_back(i);
}
}
printf("Case %d: %lld\n", cs, dp[k][n]);
}
return ;
}

算法笔记--斜率优化dp的更多相关文章

  1. APIO2010 特别行动队 & 斜率优化DP算法笔记

    做完此题之后 自己应该算是真正理解了斜率优化DP 根据状态转移方程$f[i]=max(f[j]+ax^2+bx+c),x=sum[i]-sum[j]$ 可以变形为 $f[i]=max((a*sum[j ...

  2. 斜率优化DP学习笔记

    先摆上学习的文章: orzzz:斜率优化dp学习 Accept:斜率优化DP 感谢dalao们的讲解,还是十分清晰的 斜率优化$DP$的本质是,通过转移的一些性质,避免枚举地得到最优转移 经典题:HD ...

  3. 【学习笔记】动态规划—斜率优化DP(超详细)

    [学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...

  4. 【笔记篇】斜率优化dp(一) HNOI2008玩具装箱

    斜率优化dp 本来想直接肝这玩意的结果还是被忽悠着做了两道数论 现在整天浑浑噩噩无心学习甚至都不是太想颓废是不是药丸的表现 各位要知道我就是故意要打删除线并不是因为排版错乱 反正就是一个del标签嘛并 ...

  5. 斜率优化dp(POJ1180 Uva1451)

    学这个斜率优化dp却找到这个真心容易出错的题目,其中要从n倒过来到1的确实没有想到,另外斜率优化dp的算法一开始看网上各种大牛博客自以为懂了,最后才发现是错了. 不过觉得看那些博客中都是用文字来描述, ...

  6. 斜率优化dp 的简单入门

    不想写什么详细的讲解了...而且也觉得自己很难写过某大佬(大米饼),于是建议把他的 blog 先看一遍,然后自己加了几道题目以及解析...顺便建议看看算法竞赛(蓝皮书)的 0x5A 斜率优化(P294 ...

  7. 2018.09.05 任务安排(斜率优化dp)

    描述 这道题目说的是,给出了n项必须按照顺序完成的任务,每项任务有它需要占用机器的时间和价值.现在我们有一台机器可以使用,它每次可以完成一批任务,完成这批任务所需的时间为一个启动机器的时间S加上所有任 ...

  8. 【转】斜率优化DP和四边形不等式优化DP整理

    (自己的理解:首先考虑单调队列,不行时考虑斜率,再不行就考虑不等式什么的东西) 当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重 ...

  9. 动态规划专题(五)——斜率优化DP

    前言 斜率优化\(DP\)是难倒我很久的一个算法,我花了很长时间都难以理解.后来,经过无数次的研究加以对一些例题的理解,总算啃下了这根硬骨头. 基本式子 斜率优化\(DP\)的式子略有些复杂,大致可以 ...

随机推荐

  1. spring是如何控制事务

    1.spring的核心是ioc和aop,其中ioc是将控制权交由spring容器进行管理,aop是面向切面编程,内部实现使用的是动态代理,二动态代理内部实现用的是反射.spring的事务是通过aop来 ...

  2. 01: Django rest framework 基础

    1.1 RESTful API设计规范 参考地址: http://www.cnblogs.com/wupeiqi/articles/7805382.html   1.API与用户的通信协议,总是使用H ...

  3. cscope for golang

    从 https://gist.github.com/bopjiang/11146574 下载, 做了修改. cscope-go.sh #!/bin/bash # generate cscope ind ...

  4. Vmware 安装centos7与网络配置

    一.下载linux镜像 下载地址:http://isoredirect.centos.org/centos/7/isos/x86_64/CentOS-7-x86_64-DVD-1804.iso 二.创 ...

  5. PO VO BO DTO POJO DAO之间的关系

    J2EE开发中大量的专业缩略语很是让人迷惑,尤其是跟一些高手讨论问题的时候,三分钟就被人家满口的专业术语喷晕了,PO VO BO DTO POJO DAO,一大堆的就来了. PO:persistant ...

  6. opencv学习之路(17)、边缘检测

    一.概述 二.canny边缘检测 #include "opencv2/opencv.hpp" using namespace cv; void main() { //Canny边缘 ...

  7. ubuntu18.04 安装新版本openssl

    首先我们应该知道ubuntu18.04内置了1.1.0g版本的openssl: 使用下面的apt命令更新Ubuntu存储库并安装软件包编译的软件包依赖项: sudo apt update sudo a ...

  8. centos7 挂载磁盘设置开机自启动

    1.首先查看系统磁盘情况: 2.格式化自己想要挂载的磁盘类型(ext3 ext4现在主要使用的是这些) 3.查看自己格式化磁盘的uuid(使用UUID挂载是唯一标识安全) 4.复制UUID号(别复制双 ...

  9. 盒子总结,文本属性操作,reset操作,高级选择器,高级选择器优先级,边界圆角(了解),a标签的四大伪类,背景图片操作,背景图片之精灵图

    盒子总结 ''' block: 设置宽高 1.没有设置宽,宽自适应父级的宽(子级的border+padding+width=父级的width) 2.没有设置高,高由内容撑开 设置了宽高 一定采用设置的 ...

  10. win7系统复制文件到u盘提示文件过大怎么办

    转载:https://www.xitmi.com/770.html 系统相信很多朋友都遇到过这种情况,在你拷贝文件到u盘时,u盘剩余空间明明很大,但是却复制不进去,电脑提示“对于目标文件系统 文件过大 ...