zoukankan      html  css  js  c++  java
  • 【洛谷P5785】[SDOI2012]任务安排

    【题目传送门】

    题解

    首先设计出 (n^2) 的 DP,(dp(i,j)) 表示前 (i) 个分成 (j) 段。
    后来发现空间不够,于是第二维可以压掉,反正每一次都是从前一维状态转移来。
    由于 (T) 的范围,新加入的斜率不一定单调递增,所以单调队列每次不能弹出队首元素,变成了单调栈。
    仍然是维护斜率单调递增的下凸包,但是转移的时候二分找到最优的转移点。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int INF = 0x3f3f3f3f,N = 3e5+10;
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    ll dp[N],tmp[N];
    ll s,n;
    ll sumT[N],sumC[N];
    int q[N],l,r;
    inline double X(int i){return sumC[i];}
    inline double Y(int i){return dp[i]-sumC[i]*s;}
    inline int find(double t)
    {
    	int L=l,R=r;
    	if(l==r) return q[l];//这样特判比较简洁
    	while(L<R)
    	{
    		int mid=(L+R+1)>>1;
    		if((Y(q[mid])-Y(q[mid-1]))<=(X(q[mid])-X(q[mid-1]))*t) L=mid;
    		else R=mid-1;
    	}
    	return q[L];//注意二分的是q数组下标
    }
    int main()
    {
    	n=read(),s=read();
    	for(int i=1;i<=n;i++) 
    	{
    		sumT[i]=read(),sumT[i]+=sumT[i-1];
    		sumC[i]=read(),sumC[i]+=sumC[i-1];
    	}
    	memset(dp,0x3f,sizeof(dp));//和暴力一样的初始化
    	dp[0]=0;
    	l=1,r=1;
    	for(int i=1;i<=n;i++)
    	{
    		int j=find(sumT[i]);//二分找到转移点
    		dp[i]=Y(j)+sumT[i]*(sumC[i]-sumC[j])+sumC[n]*s;
    		while(l<r&&(X(i)-X(q[r-1]))*(Y(q[r])-Y(q[r-1]))>=(X(q[r])-X(q[r-1]))*(Y(i)-Y(q[r-1]))) r--;
    		q[++r]=i; 
    	}
    	printf("%lld
    ",dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    快速开始Python/WSGI应用程序
    git clone 指定的单个目录或文件夹
    django-1-应用开发基本套路
    raid管理
    Linux下利用script命令录制并回放终端会话
    Mysqldump参数大全
    在crontab中执行脚本重要事项
    IDEA 不能搜索插件解决方案之一
    将页面整体显示为灰色的 CSS
    Linux CentOS7.5静默安装Oracle11gR2
  • 原文地址:https://www.cnblogs.com/conprour/p/15480825.html
Copyright © 2011-2022 走看看