• 洛谷3195 [HNOI2008]玩具装箱TOY(斜率优化+dp)


    qwq斜率优化好题

    第一步还是考虑最朴素的(dp)

    [dp=dp[j]+(i-j-1+sum[i]-sum[j])^2 ]

    (f[i]=sum[i]+i)

    那么考虑将上述柿子变成$$dp[i]=dp[j]+(f[i]-f[j]-1-l)^2$$

    [= dp[j]+f[j]^2-2 imes f[j] imes (2[i]-1) - 2 imes l imes f[j] ]

    当存在一个(j>k且j比k优秀的条件是)

    [dp[j]+(f[i]-f[j]-1-l)^2 < dp[k]+(f[i]-f[k]-1-l)^2 ]

    经过一波化简

    [frac{dp[j]+f[j]^2-dp[k]-f[k]^2}{f[j]-f[k]} < 2 imes (f[i]-l) ]

    然后直接套上斜率优化即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk make_pair
    #define ll long long
    #define int long long
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 4e5+1e2;
    struct Point
    {
    	int x,y,num;
    }; 
    Point q[maxn];
    int n,m;
    int sum[maxn];
    int val[maxn];
    int f[maxn];
    int head=1,tail=0;
    int dp[maxn];
    int chacheng(Point x,Point y)
    {
    	return x.x*y.y-x.y*y.x;
    }
    bool count(Point i,Point j,Point k)
    {
    	Point x,y;
    	x.x=k.x-i.x;
    	x.y=k.y-i.y;
    	y.x=k.x-j.x;
    	y.y=k.y-j.y;
    	if (chacheng(x,y)<=0) return true;
    	return false;
    }
    void push(Point x)
    {
    	while (tail>=head+1 && count(q[tail-1],q[tail],x)) tail--;
    	q[++tail]=x;
    }
    void pop(int lim)
    {
       while (tail>=head+1 && q[head+1].y-q[head].y<lim*(q[head+1].x-q[head].x)) head++; 
    } 
    signed main()
    {
      n=read();
      int l=read();
      for (int i=1;i<=n;i++) val[i]=read();
      for (int i=1;i<=n;i++) sum[i]=sum[i-1]+val[i];
      for (int i=1;i<=n;i++) f[i]=i+sum[i];
      push((Point){0,0,0});
      for (int i=1;i<=n;i++)
      {
      	 pop(2*(f[i]-l));
      	 int now = q[head].num;
      	 dp[i]=dp[now]+(f[i]-f[now]-1-l)*(f[i]-f[now]-1-l);
      	 push(Point{f[i],dp[i]+(f[i]+1)*(f[i]+1),i});
      	// cout<<i<<" "<<dp[i]<<endl;
      }
      cout<<dp[n]<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    设计模式-----简单工厂模式
    LeetCode题解002:两数相加
    LeetCode题解001:两数之和
    异常处理类-Throwable源码详解
    Windows下 gcc/g++的安装与配置
    Windows10下安装解压版MySQL教程
    Windows下Django项目搭建流程
    Linux域名服务DNS
    Linux文件共享服务 FTP,NFS 和 Samba
    操作系统:进程的概念和与程序的区别
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10175060.html
Copyright © 2020-2023  润新知