似乎又是一道cdq维护dp
这题首先要按照d[i]=a[i]-i的值分层dp。
在cdq分治中,相当于前一层dp为修改,当前层为询问。
考虑如何维护[l,mid]的修改对于[mid+1,r]的询问的影响。
列出dp方程发现只要寻找最小值即可。
然后就在维护的凸包上三分最小值的位置就好。
#include <bits/stdc++.h>
#define gc getchar()
#define N 120009
#define mid (l+r>>1)
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,m,a[N],b[N],d[N],f[N],sta[N],top,g[N];
vector<ll> p[N];
struct node
{
ll x,y,pos,k;
node(ll pos=0,ll k=0):pos(pos),k(k)
{
x=d[pos],y=g[pos]-a[pos]*pos-a[pos]+(pos+1)*pos/2;
}
bool operator <(const node &rhs) const
{
return pos<rhs.pos;
}
}q[N],now[N],st[N];
bool cmp(const node &lhs,const node &rhs)
{
return d[lhs.pos]<d[rhs.pos]||(d[lhs.pos]==d[rhs.pos]&&!lhs.k);
}
ll read()
{
ll x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
ll s=ch-'0';
while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
return s*x;
}
void solve(ll l,ll r)
{
if (l==r)
{
if (q[l].k)
g[q[l].pos]+=a[q[l].pos]+b[q[l].pos]+(q[l].pos-1)*q[l].pos/2;
return;
}
solve(l,mid);
ll num=0;
for (ll i=l;i<=mid;i++) if (!q[i].k) now[++num]=q[i];//modify in [l,mid]
for (ll i=mid+1;i<=r;i++) if (q[i].k) now[++num]=q[i];//qry in [mid+1,r]
sort(now+1,now+num+1,cmp);//sort for d
top=0;
for (ll i=1;i<=num;i++)//d is increasing
{
#define j now[i]
if (!j.k)//slope optimization
{
while (top>=2&&1.0*(j.y-st[top].y)*(st[top].x-st[top-1].x)<1.0*(st[top].y-st[top-1].y)*(j.x-st[top].x))
top--;
st[++top]=j;
}
else
{
ll L=1,R=top,len,mid_l,mid_r;//divide into three parts for the best
while (R-L>4)
{
len=(R-L)/3,mid_l=L+len,mid_r=R-len;
if (st[mid_l].x*j.pos+st[mid_l].y>st[mid_r].x*j.pos+st[mid_r].y) L=mid_l;
else R=mid_r;//min
}
while (L<=R) g[j.pos]=min(g[j.pos],st[L].x*j.pos+st[L].y),++L;
}
#undef j
}
solve(mid+1,r);
}
int main()
{
n=read();
for (ll i=1;i<=n;i++) a[i]=read(),d[i]=a[i]-i,sta[i]=g[i]=inf;
for (ll i=1;i<=n;i++) b[i]=read();
for (ll i=1;i<=n;i++)
{
if (d[i]<0) continue;
f[i]=upper_bound(sta+1,sta+n+1,d[i])-sta;
p[f[i]].push_back(i);
sta[f[i]]=min(sta[f[i]],d[i]);
}
p[0].push_back(0);
for (ll i=1;;i++)
{
if (p[i].empty())
{
ll ret=inf;
for (ll j=0,k;j<(ll)p[i-1].size();j++)
{
k=p[i-1][j];
ret=min(ret,g[k]+(a[k]*2+n-k+1)*(n-k)/2);
}
printf("%lld %lld\n",i-1,ret);
break;
}
m=0;
for (ll j=0;j<(ll)p[i-1].size();j++) q[++m]=node(p[i-1][j],0);
for (ll j=0;j<(ll)p[i].size();j++) q[++m]=node(p[i][j],1);
sort(q+1,q+m+1);
solve(1,m);
}
return 0;
}