决策单调性优化

时间:2022-12-16 14:00:03

BZOJ1563

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#define LDB long double
using namespace std;
 
  struct data{
    int po,l,r;
  }sta[100010];
   
  char st[101];
  LDB a[100010],dp[100010];
  int p,top,n,but;
  LDB stad;
 
  LDB qpow(LDB bas,int powe){
    LDB ret=1;
    for (;powe;bas*=bas){
      if (powe&1) ret*=bas;
      powe=powe>>1;   
    }
    return(ret);
  }
  
  LDB F(int po,int tar){
    return(qpow(fabs(a[tar]-a[po-1]+tar-po-stad),p)+dp[po-1]);
  }
 
  void edi(int po){
    if (F(sta[top].po,n)<F(po,n)) return;
    while (top>=but&&F(sta[top].po,sta[top].l)>F(po,sta[top].l))
      top--;
    if (top<but){
      sta[++top].po=po;
      sta[top].l=po+1;sta[top].r=n; 
    }else{
      int l=max(sta[top].l,po),r=n;
      while (l!=r){
        int mid=(l+r)>>1;
        if (F(sta[top].po,mid)>F(po,mid))
          r=mid;else l=mid+1;   
      }
      sta[++top].po=po;
      sta[top-1].r=l-1;
      sta[top].l=l;sta[top].r=n;
    }
  }
 
  int main(){
    int T;
    scanf("%d",&T);
    while (T--){
      scanf("%d%Lf%d",&n,&stad,&p);
      for (int i=1;i<=n;i++){
        scanf("%s",&st);
        a[i]=strlen(st);
        a[i]+=a[i-1];
        dp[i]=2*1e18;
      } 
       
      top=but=1;
      sta[top].po=1;sta[top].l=1;sta[top].r=n;
      dp[1]=qpow(fabs(a[1]-stad),p);
      for (int i=2;i<=n;i++){
        sta[but].l=i;
        while (top>=but&&sta[but].r<i)
          but++;
        dp[i]=F(sta[but].po,i);
        dp[i]=min(dp[i-1]+qpow(fabs(a[i]-a[i-1]-stad),p),dp[i]);
        edi(i);
      }
       
      if (dp[n]>1e18) printf("Too hard to arrange\n");else printf("%.0Lf\n",dp[n]);
      printf("--------------------\n");
    }
  }

____________________________________
BZOJ2216

#include <cstdio>
#include <iostream>
#include <cmath>
#define LDB long double
using namespace std;
 
  struct data{
    int po,l,r;
  }sta[500001];
 
  int a[500001],top,but,n,ans[500001];
 
  LDB f(int j,int i){
    return(a[j]+(sqrt(fabs((LDB)i-(LDB)j)))-a[i]);
  }
   
  void push(int po){
    if (f(sta[top].po,n)>f(po,n)) return;
    while (top>=but&&f(sta[top].po,sta[top].l)<f(po,sta[top].l))
      top--;
    if (top<but){
      sta[++top].po=po;
      sta[top].l=1;sta[top].r=n;    
    }else{
      int l=max(sta[top].l,po),r=sta[top].r;
      while (l<r){
        int mid=(l+r)>>1;
        if (f(po,mid)>f(sta[top].po,mid))
          r=mid;else l=mid+1;
      }
      sta[++top].po=po;
      sta[top-1].r=l-1;
      sta[top].l=l;sta[top].r=n;
    }
  }
   
  void work(){
    top=but=1;
    sta[1].po=1;sta[1].l=1;sta[1].r=n;
    for (int i=2;i<=n;i++){
      sta[but].l=i+1;
      while (top>=but&&sta[but].r<i) but++;
      ans[i]=max(ans[i],(int)(ceil(f(sta[but].po,i))+0.001));
      push(i);  
    }
  }
   
  int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    work();
     
    for (int i=1;i<=n/2;i++){
      int t=a[i];a[i]=a[n-i+1];a[n-i+1]=t;
      t=ans[i];ans[i]=ans[n-i+1];ans[n-i+1]=t;
    }
     
    work();
     
    for (int i=n;i>=1;i--) printf("%d\n",ans[i]);
  }