• 洛谷 P5017 [NOIP2018 普及组] 摆渡车(斜率优化dp)


    传送门


    解题思路

    设dp[i]表示在第i秒发车时前面的人一共等候了多少分钟。
    朴素方程就是枚举 (j=0 o (i-m))

    [dp[i]=min(dp[i],dp[j]+i imes(cnt[i]-cnt[j])-(a[i]-a[j])) ]

    其中 (cnt[i]) 为前 i 秒的人数,(a[i]) 为前 i 秒的所有人的到达时间的和。
    把式子拆开并移项,就变成了 y=kx+b 的形式:

    [dp[j]+a[j]=i imes cnt[j]+dp[i]+a[i]-i imes cnt[i] ]

    其中 y=dp[j]+a[j],x=cnt[j],斜率就是 i。
    然后就套上斜率优化板子即可。
    注意最后答案是

    [ans=min_{i=t}^{t+m}{dp[i]} ]

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=4e6+105;
    int n,m,t[maxn],l=1,r=1,q[maxn],dp[maxn],cnt[maxn],a[maxn],ans=1e9;
    inline double cal(int l,int r){
    	return 1.0*(dp[r]+a[r]-dp[l]-a[l])/(cnt[r]==cnt[l]?1e-9:cnt[r]-cnt[l]);
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>t[i],t[i]++;
    	sort(t+1,t+n+1);
    	int now=1;
    	for(int i=1;i<=t[n]+m;i++){
    		a[i]=a[i-1];
    		cnt[i]=cnt[i-1];
    		while(now<=n&&t[now]==i) now++,a[i]+=i,cnt[i]++;
    	}
    	q[1]=dp[0]=0;
    	for(int i=1;i<=t[n]+m;i++){
    		while(l<r&&cal(q[l],q[l+1])<=i) l++;
    		dp[i]=dp[q[l]]+i*(cnt[i]-cnt[q[l]])-(a[i]-a[q[l]]);
    		if(i<m) continue;
    		while(l<r&&cal(q[r-1],q[r])>=cal(q[r],i-m+1)) r--;
    		q[++r]=i-m+1;
    	}
    	for(int i=t[n];i<=t[n]+m;i++) ans=min(ans,dp[i]);
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    cf536c——思路题
    cf536b——优先队列的运用
    王道论坛和九度论坛
    Ubuntu 12.04 LTS 下配置 apache支持SPDY, 使用wireshark 抓包分析SPDY 协议
    vnc/route/ifconfig 配置
    MIME protocol 说明
    理解邮件传输协议(SMTP、POP3、IMAP、MIME)
    GNU C中的零长度数组
    ftp protocol
    HTTP协议头部与Keep-Alive模式详解
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15256686.html
Copyright © 2020-2023  润新知