zoukankan      html  css  js  c++  java
  • P5785 [SDOI2012]任务安排 斜率优化

    题意:

    戳这里

    分析:

    • 暴力

    (f[i][j]) 表示枚举到第 (i) 个点,分成 (j) 段时的最小代价,

    (f[i][j]=min(f[k][j-1]+(s*j+sumt[i]-sumt[k])*(sumc[i]-sumc[k])))

    然后用李超树维护转移,复杂度 (O(n^2log n))

    • 正解

    在 巨佬 的提示下发现可以优化 DP 状态,我们发现 DP 状态的第二维可以通过更改枚举状态优化掉,因为他在转移式中只出现了一次,而且与 (k) 无关

    我们设 (f[i]) 表示枚举到第 (i) 个点,之后的每一个点已经加上了由于之前重启操作带来的代价,转移式就变为了

    (f[i]=min(f[j]+s*(sumc[n]-sumc[j])+sumt[i]*(sumc[i]-sumc[j])))

    这样把之后每一个点由于之前操作带来的影响都消掉了

    然后我们发现这个式子长的很斜率优化

    我们令 (k< j)(j)(k) 转移更优,那么存在

    (f[j]+s*(sumc[n]-sumc[j])+sumt[i]*(sumc[i]-sumc[j])<f[k]+s*(sumc[n]-sumc[k])+sumt[i]*(sumc[i]-sumc[k]))

    化简得到

    (f[j]-s*sumc[j]-sumt[i]*sumc[j]<f[k]-s*sumc[k]-sumt[i]*sumc[k])

    (largefrac{(f[j]-s*sumc[j])-(f[k]-sumc[k])}{sumc[j]-sumc[k]}<sumt[i])

    但是关键在于 (|t_i|<2^8) ,也就是说 (sumt[i]) 并不单调,所以我们不能单调队列维护,我们只能维护一个下凸壳,然后每次二分寻找最优决策点转移

    复杂度 (O(nlog n))

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    
    using namespace std;
    
    namespace zzc
    {
    	inline long long read()
    	{
    		long long x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 3e5+5;
    	long long n,s,l,r;
    	long long f[maxn],c[maxn],ti[maxn],prec[maxn],pret[maxn],q[maxn];
    	
    	long long upn(int j,int k)
    	{
    		return (f[j]-s*prec[j])-(f[k]-s*prec[k]);
    	}
    	
    	long long dwn(int j,int k)
    	{
    		return (prec[j]-prec[k]);
    	}
    	
    	int solve(long long x)
    	{
    		int res=-1,ll=l,rr=r-1,mid;
    		while(ll<=rr)
    		{
    			mid=(ll+rr)>>1;
    			if(upn(q[mid+1],q[mid])>x*dwn(q[mid+1],q[mid])) res=mid,rr=mid-1;
    			else ll=mid+1;
    		}
    		return res==-1?q[r]:q[res];
    	}
    	
    	void work()
    	{
    		memset(f,0x7f,sizeof(f));
    		n=read();s=read();
    		for(int i=1;i<=n;i++) ti[i]=read(),c[i]=read(),prec[i]=prec[i-1]+c[i],pret[i]=pret[i-1]+ti[i];
    		l=0;r=0;f[0]=0;
    		for(int i=1;i<=n;i++)
    		{
    			int pos=solve(pret[i]);
    			f[i]=f[pos]+s*(prec[n]-prec[pos])+(prec[i]-prec[pos])*pret[i];
    			while(l<r&&dwn(i,q[r])*upn(q[r],q[r-1])>=dwn(q[r],q[r-1])*upn(i,q[r])) r--;
    			q[++r]=i;
    		}
    		printf("%lld
    ",f[n]);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    Silverlight 调用GP服务第一篇之发布GP服务(Geoprocessing Service)
    SQLServer中char、varchar、nchar、nvarchar的区别:
    word中带圈符号如何手动输入
    js中循环for
    正则表达式总结
    SQL Server 2008 数据库 不允许保存修改。
    多线程三种锁Monitor,lock,Mutex
    Lambda和Linq的用法
    RowDeleting和RowDeleted区别
    ASP.NET中aspx.cs页面代码中的换行方法
  • 原文地址:https://www.cnblogs.com/youth518/p/14134242.html
Copyright © 2011-2022 走看看