题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2149
题目大意:
一个长度为
n
的序列
求最多不改变的数的数量以及在这一条件下序列的总和
+
花费的最小值
题解:
首先可以令
设
f[i]
表示到第
i
个数且不改变第
那么
f[i]=max{f[j]}+1(d[j]≤d[i])
设个
g[i]
表示到第
i
个数且不改变第
那么
整理一下发现可以斜率优化DP
x=−d[i]
y=g[i]−a[i]∗(i+1)+i∗(i+1)2
k=i
用一个主席树维护凸包,每次将一个点插到对应的节点中,更新时查询对应的区域
代码:
#include <bits/stdc++.h>
using namespace std;
#define MAXN 100005
typedef long long ll;
int n;
int a[MAXN];
int b[MAXN];
ll c[MAXN];
int d[MAXN];
int e[MAXN];
int f[MAXN];
ll g[MAXN];
int cnt;
struct Point
{
ll x,y;
Point(ll _x=0,ll _y=0):x(_x),y(_y){}
friend ll operator*(const Point &a,const Point &b)
{return a.x*b.y-a.y*b.x;}
};
vector<int>tr[MAXN*32];
int ls[MAXN*32],rs[MAXN*32];
int root[MAXN],tot;
void Update(int pos,int val,int l,int r,int &rt)
{
if(!rt) rt=++tot;
while(tr[rt].size()>1&&Point(-d[tr[rt][tr[rt].size()-1]]+d[tr[rt][tr[rt].size()-2]],c[tr[rt][tr[rt].size()-1]]-c[tr[rt][tr[rt].size()-2]])*Point(-d[val]+d[tr[rt][tr[rt].size()-1]],c[val]-c[tr[rt][tr[rt].size()-1]])<=0)tr[rt].pop_back();
tr[rt].push_back(val);
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) Update(pos,val,l,mid,ls[rt]);
else Update(pos,val,mid+1,r,rs[rt]);
}
int Query(int R,int val,int l,int r,int rt)
{
if(!rt) return -1;
if(r<=R)
{
if(!tr[rt].size()) return -1;
int ll=0,rr=tr[rt].size()-1;
while(rr-ll>2)
{
int lmid=(ll+ll+rr)/3;
int rmid=(ll+rr+rr)/3;
if(c[tr[rt][lmid]]+1ll*val*d[tr[rt][lmid]]>c[tr[rt][rmid]]+1ll*val*d[tr[rt][rmid]]) ll=lmid;
else rr=rmid;
}
int re=ll;
for(int i=ll+1;i<=rr;i++)
if(c[tr[rt][i]]+1ll*val*d[tr[rt][i]]<c[tr[rt][re]]+1ll*val*d[tr[rt][re]])
re=i;
return tr[rt][re];
}
int mid=(l+r)>>1;
if(R<=mid) return Query(R,val,l,mid,ls[rt]);
int re1=Query(R,val,l,mid,ls[rt]);
int re2=Query(R,val,mid+1,r,rs[rt]);
if(re1==-1) return re2;
if(re2==-1) return re1;
if(c[re1]+1ll*val*d[re1]<c[re2]+1ll*val*d[re2])
return re1;
else return re2;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<=n;i++)scanf("%d",b+i);
for(int i=1;i<=n;i++)d[i]=a[i]-i;
f[0]=0;
for(int i=1;i<=n;i++)
{
if(d[i]<0){f[i]=-1;continue;}
if(!cnt||e[cnt]<=d[i]) e[f[i]=++cnt]=d[i];
else e[f[i]=upper_bound(e+1,e+1+cnt,d[i])-e]=d[i];
}
d[0]=0;g[0]=0;c[0]=0;Update(d[0],0,0,1000000000,root[f[0]]);
for(int i=1;i<=n;i++)
{
if(f[i]==-1){g[i]=0x3f3f3f3f3f3f3f3fll;continue;}
int tmp=Query(d[i],i,0,1000000000,root[f[i]-1]);
g[i]=c[tmp]+1ll*i*d[tmp]+1ll*i*(i-1)/2+a[i]+b[i];
c[i]=g[i]-1ll*a[i]*(i+1)+1ll*i*(i+1)/2;
Update(d[i],i,0,1000000000,root[f[i]]);
}
ll ans=0x3f3f3f3f3f3f3f3fll;
for(int i=1;i<=n;i++)
if(f[i]==cnt)
ans=min(ans,g[i]+1ll*d[i]*(n-i)+1ll*(i+1+n)*(n-i)/2);
printf("%d %lld\n",cnt,ans);
return 0;
}