Decision monotonic optimization DP + partition optimization decisions monotonic

Foreword

This would have been written \ (\ frac {2} { 3} \) up and then I forgot to save a shutdown. . .


Gorgeous dividing line

Decision monotonic optimization \ (DP \)

For similar

\[dp[i][j]=max/min(dp[k - 1][j - 1] + count(k,i))\]

May assume when the last \ (max / min \) update

\[f(i,j)=k\]

If

\[\forall i,j\in[1,n],s.t. i < j \Rightarrow f(i,k)<=f(j,k)\]

I can call her with decision-making monotonic

example

[HNOI2008] packing toys TOY

I will not summarize the meaning of the questions

It is easy to launch equation of state title

\[dp[i]=min(dp[j-1]+count(i,j))\]

Seat of your pants is a decision monotony

In fact, to prove

But I will not be too dishes

Now that the decision has monotonic

Then for each decision point we can come up with a decision interval

Use a deque maintenance interval decision and decision point

Before each cycle

The interval \ (. R <i \) a truncated

Then by current point of decision point to see if the contribution is smaller than on the back of the queue

Already

while(l <= r&&dp[i] + count(q[r].l,i) <= dp[q[r].pos] + count(q[r].l,q[r].pos)) r--;

Note \ (while \) after the end of the sentence but also about special

\[dp[i] + count(q[r].l,i) <= dp[q[r].pos] + count(q[r].l,q[r].pos)\]

not necessarily

\(\forall x \in[q[r].l,q[r].r]\Rightarrow dp[i] + count(x,i) > dp[q[r].pos] + count(x,q[r].pos)\)

So even half to find what that particular location

Because the decision point monotonic \ (\ Rightarrow \) decision section monotonic \ (\ Rightarrow \) double-ended queue maintained monotonicity

And monotonous queue similar to each point of entry and delete only once

But there are two points

Time complexity \ (O (nlogn) \)

\(Code\)

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define reg register int
#define isdigit(x) ('0' <= x&&x <= '9')
template<typename T>
inline T Read(T Type)
{
    T x = 0,f = 1;
    char a = getchar();
    while(!isdigit(a)) {if(a == '-') f = -1;a = getchar();}
    while(isdigit(a)) {x = (x << 1) + (x << 3) + (a ^ '0');a = getchar();}
    return x * f;
}
typedef long long ll;
const int MAXN = 50010;
int n,L,a[MAXN];
ll dp[MAXN],sum[MAXN];
struct node
{
    int pos,l,r;
    void ass(int Pos,int L,int R) {pos = Pos,l = L,r = R;}
}q[MAXN];
inline ll co(ll x) {return x * x;}
inline ll count(int i,int j) {return co(sum[i] - sum[j] + i - j - 1 - L);}
inline int get_(int x,node seq)
{
    int l = seq.l,r = seq.r;
    while(l <= r)
    {
        int mid = l + r >> 1;
        if(dp[x] + count(mid,x) <= dp[seq.pos] + count(mid,seq.pos))
        {
            if(r == mid) return r;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    return l;
}
int main()
{   n = Read(1),L = Read(1);
    for(reg i = 1;i <= n;i++) sum[i] = (a[i] = Read(1)) + sum[i - 1];
    memset(dp,0x7f7f7f,sizeof(dp));
    dp[0] = 0;
    int l = 1,r = 0;
    q[++r].ass(0,1,n);
    for(reg i = 1;i <= n;i++)
    {
        while(q[l].r < i) l++;
        dp[i] = dp[q[l].pos] + count(i,q[l].pos);
        q[l].l = i + 1;
        while(l <= r&&dp[i] + count(q[r].l,i) <= dp[q[r].pos] + count(q[r].l,q[r].pos)) r--;
        int pos = get_(i,q[r]);
        q[r].r = pos - 1;
        if(pos <= n) q[++r].ass(i,pos,n);
    }
    printf("%lld\n",dp[n]);
    return 0;
}

Such \ (DP \) usually can re-optimization

Or it may be a queue with a monotonous slope

But the decision monotonicity really want, good and better than violence to achieve the characteristics we often use

Partition optimization decisions monotonic

Because the decision-making monotonic

Then you can use the divide and conquer optimization

CF321E Ciel and Gondolas

#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define reg register int
#define isdigit(x) ('0' <= x&&x <= '9')
template<typename T>
inline T Read(T Type)
{
    T x = 0,f = 1;
    char a = getchar();
    while(!isdigit(a)) {if(a == '-') f = -1;a = getchar();}
    while(isdigit(a)) {x = (x << 1) + (x << 3) + (a ^ '0');a = getchar();}
    return x * f;
}
const int MAXN = 4010,inf = 1000000000;
int sum[MAXN][MAXN],dp[MAXN][810];
inline int count(int i,int j) 
{return sum[i][i] - sum[i][j - 1] - sum[j - 1][i] + sum[j - 1][j - 1];}
inline void dfs(int k,int l,int r,int opl,int opr)
{
    if(l > r) return;
    int mid = l + r >> 1;
    int minl = inf,id;
    for(int i = opl;i <= min(opr,mid);i++)
    {
        int cur = dp[i - 1][k - 1] + count(mid,i);
        if(cur < minl) minl = cur,id = i;
    }
    dp[mid][k] = minl;
    dfs(k,l,mid - 1,opl,id);
    dfs(k,mid + 1,r,id,opr);
}
int main()
{
    int n = Read(1),k = Read(1);
    for(reg i = 1;i <= n;i++)
        for(reg j = 1;j <= n;j++)
        {
             int v = Read(1);
             sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + v;
        }
    for(reg i = 1;i <= n;i++) dp[i][0] = inf;
    for(reg i = 1;i <= k;i++) dfs(i,1,n,1,n);
    printf("%d",dp[n][k] / 2);
    return 0;   
} 

Guess you like

Origin www.cnblogs.com/resftlmuttmotw/p/12002741.html