货物分组(加强版)

自己搞的加强版

设:

\[add_i=\sum_{j=1}^iw_i \]

\[sum=add_n \]

\[S_{i,j}=\max(w_k)-\min(w_k),k\in[i,j],k\in Z \]

\[f_{i,x}=\min(f_{j,x-1}+(add_i-add_j)\times x+S_{j+1,i}) \]

其中 \(f_{i,x}\) 表示到第 \(i\) 个位置,分 \(x\) 组的花费。

记起来某道题,得到了启发,想到了优化 DP 式的方法。

初始化 \(f_0\)\(sum\)

\[f_i=\min(f_j+sum-add_{i}+S_{j+1,i}) \]

等于把这个费用塞到前面而非后面,就可以不用记录 \(x\) 了。

具体的,就是维护一个单调队列。

for(i=1;i<=n;i++)
    {
        for(;head<=tail&&add[i]-add[d[head]]>W;head++);
        f[i]=0x3f3f3f3f3f3f3f3f;
        for(j=head;j<=tail;j++)
        {
            int x=d[j]+1;
            int S=work(x,i);//线段树直接跑区间最值
            if(f[x-1]+add[n]-add[i]+S<f[i])
            {
                f[i]=f[x-1]+add[n]-add[i]+S;
            }
        }
        // if(deep[i]<deep[i-1])printf("false\n");
        for(;head<=tail&&f[i]<=f[d[tail]];tail--);
        d[++tail]=i;
    }

考虑优化:

如果记录这个分组数 \(x\),表示的是到当前位置分 \(x\) 组最优。

设这个东西为 \(deep_i\)

\(deep_i\) 单调不减,这个应该是比较显然的,当然如果你觉得有哪里说不过去,也欢迎指出。

有了 \(deep_i\) 单调不减的结论,加上从二维 DP 的式子中可以知道:每个组数为 \(x\) 的都由一个 \(x-1\) 得来,我们就可以在代码里加上这样的优化:


    for(;deep[d[head]]+1<deep[i];head++);

简单的理解:当前的 \(deep\) 已经比队头的 \(deep\) 至少大 \(2\) 了,后面的 \(deep\) 不减,那么队头元素就再也用不到了,弹出。

至于为什么可以这样操作,因为既然 \(deep\) 是当前最优分组数,那么其他的分组数就都是无用的策略。(回归到一维 DP 的角度考虑)


\(\operatorname {Question}:\) 这不就是常数优化吗?感觉完全能卡到 \(\operatorname O(n^2)\)

对于这个问题,我一开始认为我这个代码,对于每个相同最优分组数的位置,我只会保存最后一个。但实际上不是,只需要出现这样的连续数对 \(y_1,\dots ,y_n,x_1,x_2\) 满足 \(x_2\) 加入后 \(S\) 的增大值大于 \(x_2\) 便足以推翻这个结论。

那么一种很差的数据(我个人感觉是最坏的情况,但不敢肯定),就是:

\[\frac{m}{2},\frac{m}{4},\dots 1 \]

这样的话,对于每一组相同 \(deep\)\(f\) 值,我全部都得保留,然后因为我每次最多保留两组数,所以我这个代码的理论复杂度为 \(\operatorname O(2n\log \operatorname W \log n)\)

那么 \(10^5\) 的数据是绰绰有余的,但是对于加强的数据 \(n\le 6\times 10^6,\operatorname W\le 10^7\),该怎么跑过去呢?

如果把线段树换成 st 表,这个 \(\log n\) 就可以删去,我这波将绝杀,但是问题也很明显:空间会炸。

可惜换不得

但是,算了算,这个空间是 \(522\) MB 左右。

搞了个期望 \(\operatorname O(1)\) 的分块 RMQ,总算是过了这题。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=6e6+3;
const int M=2460;
struct milk
{
    int l,r;
    int s1_l[M],s1_r[M];
    int s2_l[M],s2_r[M];
}t[M];
int s_1[M][M];
int s_2[M][M];
int to[N];
int a[N];
LL f[N];
LL add[N];
int deep[N];
int d[N];
int n,W;
int nam;
int maxx,minx;
inline void init()
{
    int lens=sqrt(n);
    int ks=n/lens;
    for(int i=1;i<=ks;i++)
    {
        t[i].l=t[i-1].r+1;
        t[i].r=lens*i;
        t[i].s1_l[0]=t[i].s1_r[lens+1]=0;
        t[i].s2_l[0]=t[i].s2_r[lens+1]=0x3f3f3f3f;
        for(int j=1;j<=lens;j++)
        {
            t[i].s1_l[j]=max(t[i].s1_l[j-1],a[j+t[i].l-1]);
            t[i].s2_l[j]=min(t[i].s2_l[j-1],a[j+t[i].l-1]);
        }
        for(int j=lens;j>=1;j--)
        {
            t[i].s1_r[j]=max(t[i].s1_r[j+1],a[j+t[i].l-1]);
            t[i].s2_r[j]=min(t[i].s2_r[j+1],a[j+t[i].l-1]);
        }
    }
    if(n%lens>0)
    {
        ks++;
        t[ks].l=t[ks-1].r+1;
        t[ks].r=n;
        lens=t[ks].r-t[ks].l+1;
        int i=ks;
        t[i].s1_l[0]=t[i].s1_r[lens+1]=0;
        t[i].s2_l[0]=t[i].s2_r[lens+1]=0x3f3f3f3f;
        for(int j=1;j<=lens;j++)
        {
            t[i].s1_l[j]=max(t[i].s1_l[j-1],a[j+t[i].l-1]);
            t[i].s2_l[j]=min(t[i].s2_l[j-1],a[j+t[i].l-1]);
        }
        for(int j=lens;j>=1;j--)
        {
            t[i].s1_r[j]=max(t[i].s1_r[j+1],a[j+t[i].l-1]);
            t[i].s2_r[j]=min(t[i].s2_r[j+1],a[j+t[i].l-1]);
        }
    }
    for(int i=1;i<=ks;i++)
    {
        s_1[i][i]=t[i].s1_r[1];
        s_2[i][i]=t[i].s2_r[1];
        for(int j=i+1;j<=ks;j++)
        {
            s_1[i][j]=max(s_1[i][j-1],t[j].s1_r[1]);
            s_2[i][j]=min(s_2[i][j-1],t[j].s2_r[1]);
        }

        for(int j=t[i].l;j<=t[i].r;j++)to[j]=i;
    }
    return;
}
inline int work(int x,int y)
{
    int maxx,minx;
    if(to[x]==to[y])
    {
        maxx=0,minx=0x3f3f3f3f;
        for(int i=x;i<=y;i++)maxx=max(maxx,a[i]),minx=min(minx,a[i]);
        return maxx-minx;
    }
    int l=to[x],r=to[y];
    maxx=max(t[l].s1_r[x-t[l].l+1],t[r].s1_l[y-t[r].l+1]);
    minx=min(t[l].s2_r[x-t[l].l+1],t[r].s2_l[y-t[r].l+1]);
    if(l+2<=r)
    {
        maxx=max(maxx,s_1[l+1][r-1]);
        minx=min(minx,s_2[l+1][r-1]);
    }
    return maxx-minx;
}
int rin()
{
    int s=0;
    char c=getchar();
    bool bj=0;
    for(;(c>'9'||c<'0')&&c!='-';c=getchar());
    if(c=='-')c=getchar(),bj=true;
    for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
    if(bj)return -s;
    return s;
}
int main()
{
    // freopen("data24.in","r",stdin);
    // freopen("data24.out","w",stdout);
    int i,j;
    n=rin();W=rin();
    for(i=1;i<=n;i++)
    {
        a[i]=rin();
        add[i]=add[i-1]+a[i];
    }
    init();
    int head=1,tail=0;
    d[++tail]=0;
    f[0]=add[n];
    deep[0]=0;
    for(i=1;i<=n;i++)
    {
        for(;head<=tail&&add[i]-add[d[head]]>W;head++);
        f[i]=0x3f3f3f3f3f3f3f3f;
        for(j=head;j<=tail;j++)
        {
            int x=d[j]+1;
            int S=work(x,i);
            if(f[x-1]+add[n]-add[i]+S<f[i])
            {
                f[i]=f[x-1]+add[n]-add[i]+S;
                deep[i]=deep[d[j]]+1;
            }
        }
        for(;deep[d[head]]+1<deep[i];head++);
        for(;head<=tail&&f[i]<=f[d[tail]];tail--);
        d[++tail]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}
posted @ 2020-09-26 20:04  zjjws  阅读(167)  评论(0编辑  收藏  举报