[JZOJ5646]【NOI2018模拟4.12】染色游戏

Description

这里写图片描述
这里写图片描述

Solution

容易看出不考虑a的限制的话这是一个斜率优化的式子

这就变成了一个二维偏序,既要下标又要权值

当然可以用二维数据结构,如果希望将问题降维的话,排序是一个好的选择

这样就有一种 O(Nlog2N) 的做法,先按a从小到大排序,然后由于这个点只会转移到它后面的点,那么用李超树维护凸包,动态加线段即可

理论上是不能通过的,实际上一批人过掉了这题还跑的贼快。。

接下来讲 O(NlogN) 的做法

CDQ分治也是好的办法
考虑按权值排序后分治

递归 [l,mid] ,计算 [l,mid] [mid+1,r] 的贡献,然后再递归 [mid+1,r]

此时我们就可以将它们分别按下标排好序,然后直接做斜率优化DP即可

注意如果直接sort还是 O(Nlog2N)
可以用归并排序先预处理好所有区间按下标排序的结果

复杂度 O(NlogN)

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 1000005
#define LL long long
using namespace std;
int a[N],w[N],n,c[N],dt[20][N];
LL f[N],g[N],ans,d[N]; 
bool cmp(int x,int y)
{
    return (a[x]<a[y])||(a[x]==a[y]&&x<y);
}
void doit(int l,int r,int t)
{
    if(l==r) f[w[l]]=max(f[w[l]],a[w[l]]-(LL)(w[l]-1)*(w[l])/2),g[w[l]]=(LL)2*f[w[l]]-(LL)w[l]*w[l]-w[l],ans=max(ans,f[w[l]]-(LL)(n-w[l])*(n-w[l]+1)/2);
    else
    {
        int mid=(l+r)/2;
        doit(l,mid,t+1);
        int j=l;
        int x=1,y=0;
        d[0]=d[1]=0;
        fo(i,mid+1,r)
        {
            int p=dt[t][i];
            while(dt[t][j]<p&&j<=mid) 
            {
                LL q=dt[t][j];
                while(x<y&&-(g[q]-g[d[y]])*(d[y]-d[y-1])<=-(g[d[y]]-g[d[y-1]])*(q-d[y])) y--;
                d[++y]=q;
                j++;    
            }
            while(x<y&&-(g[d[x+1]]-g[d[x]])<=(LL)2*p*(d[x+1]-d[x])) x++;
            if(x<=y&&x) f[p]=max(f[p],f[d[x]]+a[p]-(LL)(p-d[x]-1)*(p-d[x])/2);
            g[p]=(LL)2*f[p]-p*p-p;
            ans=max(ans,f[p]-(LL)(n-p)*(n-p+1)/2);
        }
        doit(mid+1,r,t+1);
    }
}
void gsort(int l,int r,int t)
{
    if(l==r) dt[t][l]=w[l];
    else
    {
        int mid=(l+r)/2;    
        gsort(l,mid,t+1),gsort(mid+1,r,t+1);
        int x=l,y=mid+1,le=l-1;
        while(x<=mid&&y<=r) 
        {
            if(dt[t+1][x]<dt[t+1][y]) dt[t][++le]=dt[t+1][x++];
            else dt[t][++le]=dt[t+1][y++];
        }
        while(x<=mid) dt[t][++le]=dt[t+1][x++];
        while(y<=r) dt[t][++le]=dt[t+1][y++];
    }
}
int main()
{
    cin>>n;
    fo(i,1,n) scanf("%d",&a[i]),w[i]=i,f[i]=-1e15;
    sort(w+1,w+n+1,cmp);
    f[0]=0;
    gsort(1,n,0);
    ans=-(LL)n*(LL)(n+1)/2;
    doit(1,n,1);
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/80024899