Atcoder Regular Contest 066 F genocide【JZOJ5451】

題目

這裏寫圖片描述

分析

s[i] 表示a前綴和。
f[i] 表示做完了1~i的友誼顆粒的最優值(不一定選i),那麼轉移方程爲

f[i]=max{f[i1],max{f[j]s[i]+s[j]+(ij)(ij+1)2}}
,用斜率優化來處理這個。
類似的,設gi 表示做完了i~n的友誼顆粒的最優值(不一定選i),
將a翻轉,像f一樣做一遍,再將g翻轉就可以了。
對於詢問(p,x),如果我們不選擇p,那麼答案就是f[i1]+g[i+1]
如果我們選擇了p,我們再設F[i] 表示,必選i的最優值。
F[i]=max{f[j]+g[k]+(kj+1)(kj+2)2}(j<i<k)

時間複雜度是O(N2)
如何可以更快的求出F[i] 呢,
分治,假設當前做到[l,r] ,左端點[l,mid] ,i和右端點在[mid+1,r]
tmp[i] 表示做完了左端點~i的友誼顆粒,且必選i的最優值
我們將[l1,mid1] 的端點扔進斜率優化的單調棧,掃一遍[mid+1,r] 求出tmp,
tmp[i]=max{f[j]+g[i+1]+(ij+1)(ij+2)2}(j[l1,mid1]<i[mid+1,r])

那麼F[i] 就是當前區間tmp[i] 的後綴max
因爲只考慮了i在[mid+1,r] 的情況,反過來做一遍就可以了。
那麼選擇了p的的最優值就是F[p]+a[p]x
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
#include <stack>
using namespace std;
const int maxlongint=2147483647;
const int mo=1e9+7;
const int N=1000005;
#define rev(h) for(int i=1;i<=n/2;i++) swap(h[i],h[n-i+1])
#define val(h,j,k) 1ll*(h[j]-h[k]+s[j]-s[k]-1ll*j*1.0/2+1ll*k*1.0/2+1ll*j*j*1.0/2-1ll*k*k*1.0/2)*1.0/(j-k)
int n,m,t[N],top;
long long a[N],s[N],f[N],g[N],F[N],tmp[N];
void dg(long long *f,long long *g,int l,int r)
{
    if(l==r)
    {
        F[l]=max(F[l],f[l-1]+g[l+1]+1-a[l]);
        return;
    }
    int mid=(l+r)>>1;
    top=0;
    for(int i=l-1;i<=mid;i++)
    {
        for(;top>1 && val(f,i,t[top])>=val(f,t[top],t[top-1]);) top--;
        t[++top]=i;
    }
    for(int i=mid+1;i<=r;i++)
    {
        for(;top>1 && val(f,t[top],t[top-1])<=i;) top--;
        int j=t[top];
        tmp[i]=f[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2+g[i+1];
    }
    for(int i=r-1;i>=mid+1;i--) tmp[i]=max(tmp[i],tmp[i+1]);
    for(int i=r;i>=mid+1;i--) F[i]=max(F[i],tmp[i]);
    dg(f,g,l,mid),dg(f,g,mid+1,r);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),s[i]=s[i-1]+a[i],F[i]=-a[i]+1;
    t[top=1]=0;
    for(int i=1;i<=n;i++)
    {
        for(;top>1 && val(f,t[top],t[top-1])<=i;) top--;
        int j=t[top];
        f[i]=max(f[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2,f[i-1]);
        for(;top>1 && val(f,i,t[top])>=val(f,t[top],t[top-1]);) top--;
        t[++top]=i;
    }
    rev(a);
    t[top=1]=0;
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    for(int i=1;i<=n;i++)
    {
        for(;top>1 && val(g,t[top],t[top-1])<=i;) top--;
        int j=t[top];
        g[i]=max(g[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2,g[i-1]);
        for(;top>1 && val(g,i,t[top])>=val(g,t[top],t[top-1]);) top--;
        t[++top]=i;
    }
    rev(a);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    rev(g);
    dg(f,g,1,n);
    rev(a);
    rev(g);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    rev(F);
    rev(f);
    dg(g,f,1,n);
    rev(F);
    rev(g);
    rev(f);
    rev(a);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        long long p,x;
        scanf("%lld%lld",&p,&x);
        printf("%lld\n",max(f[p-1]+g[p+1],F[p]+a[p]-x));
    }
}
發佈了219 篇原創文章 · 獲贊 229 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章