51nod 1488 帕斯卡小三角 斜率优化

思路:斜率优化

提交:\(2\)

错因:二分写挂

题解:

首先观察可知,

对于点\(f(X,Y)\),一定是由某个点\((1,p)\),先向下走,再向右下走。

并且有个显然的性质,若从\((1,p)\)向下走,则\(a[p]=min(a[i]),i\in [p,Y]\)(要不然直接从后面的更小的那个位置向下走,再向右下走)

还有一个显然的性质,若\(i<j\)\(i\)\(j\)更优,则\(a[i]>a[j]\)(上面的结论)

\(s[i]=\sum_{j=1}^i a[j]\)

那么对于点\(f(X,Y)\)\(ans=s[Y]-s[i]+a[i]*(X-Y+i),i\in [max(1,Y-X),Y]\)

这个式子是可以斜率优化的:\(s[i]-a[i]*i=(X-Y)*a[i]+s[Y]-ans\)

要最小化\(ans\),就是最大化\(s[Y]-ans\),所以我们用单调栈维护下降斜率(上凸包),每次先查找合法区间\(i\in [max(1,Y-X),Y]\),然后再在单调栈中二分斜率。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register int
using namespace std;
namespace Luitaryi {
template<class I> inline I g(I& x) { x=0;
  register I f=1; register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
  do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=1e5+10;
int n,m,a[N],s[N],stk[N],ans[N],t;
struct node {int x,y,p;
  inline bool operator < (const node& that) const {return y<that.y;}
}b[N];
inline int getlim(int pos) {
  R l=1,r=t; while(l<r) { R md=l+r>>1;
    if(stk[md]<pos) l=md+1; else r=md;
  } return l;
}
inline double calc(int i,int j) {return ((double)(s[i]-a[i]*i)-(double)(s[j]-a[j]*j))/(double)(a[i]-a[j]);}
inline void main() { 
  g(n); for(R i=1;i<=n;++i) g(a[i]),s[i]=s[i-1]+a[i];
  g(m); for(R i=1;i<=m;++i) g(b[i].x),g(b[i].y),b[i].p=i;
  sort(b+1,b+m+1); for(R i=1,j=1;i<=n;++i) {
    while(t&&a[stk[t]]>=a[i]) --t;
    while(t>1&&calc(stk[t],i)>=calc(stk[t-1],i)) --t;
    stk[++t]=i; while(b[j].y==i&&j<=m) {
      R l=getlim(b[j].y-b[j].x),r=t; 
      while(l<r) { R md=l+r>>1;
        if(calc(stk[md],stk[md+1])<b[j].x-b[j].y) r=md;
        else l=md+1;
      } l=stk[l],r=b[j].y; 
      ans[b[j].p]=s[r]-s[l]+a[l]*(b[j].x-r+l); ++j;
    }
  } for(R i=1;i<=m;++i) printf("%d\n",ans[i]);
}
} signed main() {Luitaryi::main(); return 0;}

2019.08.12
88

posted @ 2019-08-12 09:13  LuitaryiJack  阅读(211)  评论(0编辑  收藏  举报