zoukankan      html  css  js  c++  java
  • [CEOI2004]锯木厂选址

    洛谷题目链接

    纪念自己推出了第一道斜率优化!

    变量声明:

    $sum[i]$表示前$i$棵树的总重

    $dis[i]$表示从开头到第$i$棵树的距离

    $pay[i]$表示在第$i$处设立厂,花费是多少,只考虑$i$之前的

    $f[i]$表示在第$i$处设立第二个厂的总最小花费

    那么假设第一个厂建在$j$处,第二个厂建在$i$处,那么$i$~$j$部分的木材运送到$i$处需要的花费则为

    $pay[i]-pay[j]-sum[j]*(dis[i]-dis[j])$

    那么$i$~$n+1$的花费则为

      $pay[n+1]-pay[i]-sum[i]*(dis[n+1]-dis[i])$

    而$1$~$j$的花费就是

    $pay[j]$

    总花费就是上面加起来

    $pay[n+1]-sum[j]*(dis[i]-dis[j])-sum[i]*(dis[n+1]-dis[i])$

    那么可以得出普通的转移式:(对于$1$~$i$中的每个数$j$)

    $f[i]=min(pay[n+1]-sum[j]*(dis[i]-dis[j])-sum[i]*(dis[n+1]-dis[i]))(j<i)$

     整理一下:

    $1、$去掉$min$,选择性的去括号:

    $f[i]=pay[n+1]-sum[j]*dis[i]+sum[j]*dis[j]-sum[i]*(dis[n+1]-dis[i])$

    $2、$整理成一次函数$y=kx+b$的形式:

    $sum[j]*dis[j]=dis[i]*sum[j]+f[i]-sum[i]*(dis[n+1]-dis[i])$

    那么用单调队列维护一下就行了

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 20007
    using namespace std;
    int n;
    int sum[N],dis[N],pay[N];
    int que[N],f[N];
    int X(int i)
    {
    	return sum[i];
    }
    int Y(int i)
    {
    	return sum[i]*dis[i];
    }
    int Get_k(int i,int j)
    {
    	return (Y(i)-Y(j))/(X(i)-X(j));
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%d%d",&sum[i],&dis[i+1]); 
    		sum[i]+=sum[i-1];
    		pay[i+1]=pay[i]+sum[i]*dis[i+1];
    		dis[i+1]+=dis[i];
    	}
    	sum[n+1]=sum[n];
    	int head=1,tail=1;
    	for(int i=1;i<=n;++i)
    	{
    		while(head<tail&&Get_k(que[head],que[head+1])<dis[i])
    			++head;
    		f[i]=pay[n+1]-sum[que[head]]*(dis[i]-dis[que[head]])-sum[i]*(dis[n+1]-dis[i]);
    		while(head<tail&&Get_k(i,que[tail-1])<Get_k(que[tail],que[tail-1]))//Q1
    			--tail;
    		que[++tail]=i;
    	}
    	int ans=0x3f3f3f3f;
    	for(int i=1;i<=n;++i)
    		ans=min(ans,f[i]);
    	printf("%d",ans);
    }
    

    对于代码中$Q1$,应该可以写成如下吧$qwq$(我也不确定):

    while(head<tail&&Get_k(i,que[tail])<Get_k(que[tail],que[tail-1]))
    			--tail;
    

    两种方式应该是理解不同,一个是在点的方面思考,一个是在线的方面思考,亲测都对(本题)

     

  • 相关阅读:
    ROS安装
    安装octomap的问题与解决方案
    陀螺仪和加速度计MPU6050的单位换算方法
    概率基础
    Ubuntu使用多线程cmake时出现undefined reference to `pthread_create'
    C++中的static关键字的总结
    QSignalMapper的使用和使用场景
    Linux下C ,C ++, Qt开发环境
    void operator()()的功能
    C++11多线程编程--线程创建
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/10218559.html
Copyright © 2011-2022 走看看