• 洛谷 P2120 [ZJOI2007]仓库建设


    题目链接

    Step1

    朴素DP

    for(int i=1;i<=n;i++){
    	    for(int j=0;j<i;j++){
    		    long long x=0;
    			for(int k=j+1;k<=i;k++) x+=p[k]*(a[i]-a[k]);
    			dp[i]=min(dp[i],dp[j]+x+c[i]);
    		}
    	}
    

    Step 2

    前缀和优化

    for(int i=1;i<=n;i++) s1[i]=s1[i-1]+p[i],s2[i]=s2[i-1]+p[i]*a[i];
    
    for(int i=1;i<=n;i++){
    	for(int j=0;j<i;j++){
    		dp[i]=min(dp[i],dp[j]+a[i]*(s1[i]-s1[j])-(s2[i]-s2[j])+c[i]); 
        }
    }
    

    Step 3

    单调队列优化

    /*
    
    dp[i]=min(dp[i],dp[j]+a[i]*(s1[i]-s1[j])-(s2[i]-s2[j])+c[i]);
    
    j<k&& k is better
    
    dp[j]+a[i]*(s1[i]-s1[j])-(s2[i]-s2[j])+c[i]>dp[k]+a[i]*(s1[i]-s1[k])-(s2[i]-s2[k])+c[i]
    
    dp[j]+a[i]*s1[i]-a[i]*s1[j]-s2[i]+s2[j]+c[i]>dp[k]+a[i]*s1[i]-a[i]*s1[k]-s2[i]+s2[k]+c[i]
    
    dp[j]-a[i]*s1[j]+s2[j]>dp[k]-a[i]*s1[k]+s2[k]
    
    (dp[j]+s2[j])-(dp[k]+s2[k])>a[i]*(s1[j]-s1[k])
    
    (dp[j]+s2[j])-(dp[k]+s2[k])/(s1[j]-s1[k])>a[i]
    
    (dp[k]+s2[k])-(dp[j]+s2[j])/(s1[k]-s1[j])>a[i]
    
    a[i]递增
    
    斜率也要递增
    
    单调队列维护 
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    
    int read(){
    	int x=0; char c=getchar(); int flag=1;
    	while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); }
    	while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); }
    	return x*flag;
    }
    
    const int N=1e6+50;
    
    int n;
    long long a[N],p[N],c[N];
    long long s1[N],s2[N];
    long long dp[N];
    
    int q[N];
    int l,r;
    
    signed main(){
        n=read();
        for(int i=1;i<=n;i++){
    	    a[i]=read(),p[i]=read(),c[i]=read();
    	    dp[i]=1e18;
    	}
    
        for(int i=1;i<=n;i++) s1[i]=s1[i-1]+p[i],s2[i]=s2[i-1]+p[i]*a[i];
    
        l=r=1; q[1]=0;
        for(int i=1;i<=n;i++){
    	    while(r>l){
    		    if((dp[q[l+1]]+s2[q[l+1]]-dp[q[l]]-s2[q[l]])<a[i]*(s1[q[l+1]]-s1[q[l]])) ++l;//当前的队头斜率小于a[i],即队头无法对答案有贡献,弹出
    		    else break;
    		}
    		
    		dp[i]=min(dp[i],dp[q[l]]+a[i]*(s1[i]-s1[q[l]])-(s2[i]-s2[q[l]])+c[i]);
    		
    		while(r>l){
    		    if((dp[q[r]]+s2[q[r]]-dp[q[r-1]]-s2[q[r-1]])*(s1[i]-s1[q[r]])>=(dp[i]+s2[i]-dp[q[r]]-s2[q[r]])*(s1[q[r]]-s1[q[r-1]])) --r;//维护队尾斜率递增
    			else break; 
    		}
    		
    		q[++r]=i;
    	}
    
    	printf("%lld
    ",dp[n]);
    	
        return 0;
    }
    
  • 相关阅读:
    TensorFlow简易学习[3]:实现神经网络
    TensorFlow简易学习[2]:实现线性回归
    TensorFlow简易学习[1]:基本概念和操作示例
    [转]概念:结构化数据、半结构化数据、非结构数据
    SIP简介
    Flask
    vue项目中的常见问题
    为什么java中用枚举实现单例模式会更好
    20道Java面试必考题
    Java面试题(二)
  • 原文地址:https://www.cnblogs.com/zzhzzh123/p/12235613.html
Copyright © 2020-2023  润新知