zoukankan      html  css  js  c++  java
  • 【LG5017】[NOIP2018pj]摆渡车

    【LG5017】[NOIP2018pj]摆渡车

    题面

    洛谷

    题解

    震惊!普及组竟然考斜率优化???

    当然有其他的方法

    首先我们转化一下模型

    此题可以变为:

    在一根时间轴上有一些点,每个时间点(i)有一个权值(c_i)(即在(i)开始等待人数,没有则为(0))

    要求选一些时间点,每个时间点间隔不小于(m)

    使得每个点的权值乘上它与第一个大于等于它时间的已选择的时间点到它的距离之和最小 感觉讲得好复杂

    (dp[i])表示当我们强制选时间点(i)的最小值

    则有转移方程(dp[i]=min{dp[j]+sum_{k=j+1}^i{(i-k)*c_k}}) (()(0)(leq)(j)(leq)(i-m)())

    次数直接转移的复杂度为(O(n^3))

    考虑怎么优化,设

    (sum1[i]=sum_{j=0}^i{c_j})

    (sum2[i]=sum_{j=0}^i{c_j*j})

    然后方程化为(dp[i]=min dp[j]+i*sum1[i]-i*sum1[j]-sum2[i]+sum2[j]) (()(0)(leq)(j)(leq)(i-m)())

    此时复杂度为(O(n^2))

    继续优化,此时用上斜率优化

    去掉(min),则

    (dp[i]=dp[j]+i*sum1[i]-i*sum1[j]-sum2[i]+sum2[j])

    移项得(dp[j]+sum2[j]=i*sum1[j]+dp[i]-i*sum1[j]+sum2[i])

    (dp[j]+sum2[j])视为(y)

    (i)视为(k)

    (sum1[j])视为(x)

    队列优化下凸壳即可

    复杂度(O(n))

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <climits> 
    using namespace std;
    #define MAX_T 4100000 
    int N, M, c[MAX_T]; 
    int maxt, sum1[MAX_T], sum2[MAX_T]; 
    int dp[MAX_T], q[MAX_T]; 
    #define y(i) (dp[i] + sum2[i])
    #define k(i) (i)
    #define x(i) (sum1[i]) 
    int main() { 
        cin >> N >> M; 
        for (int t, i = 1; i <= N; i++) cin >> t, c[t]++, maxt = max(maxt, t); 
        sum1[0] = c[0], sum2[0] = 0;  
        for (int i = 1; i < maxt + M; i++) { 
            sum1[i] = sum1[i - 1] + c[i]; 
            sum2[i] = sum2[i - 1] + i * c[i]; 
        } 
        int ans = INT_MAX; 
        int l = 1, r = 0; 
        for (int i = 0; i < maxt + M; i++) { 
            if (i - M >= 0) { 
                while (l < r && 1ll * (y(q[r]) - y(q[r - 1])) * (x(i - M) - x(q[r])) >= 
                                1ll * (y(i - M) - y(q[r])) * (x(q[r]) - x(q[r - 1]))) -- r; 
                q[++r] = i - M; 
            } 
            while (l < r && 1ll * (y(q[l + 1]) - y(q[l])) <= 
                            1ll * k(i) * (x(q[l + 1]) - x(q[l]))) ++l; 
            dp[i] = i * sum1[i] - sum2[i]; 
            int j = q[l]; if (l <= r) dp[i] = min(dp[i], dp[j] + i * sum1[i] - i * sum1[j] - sum2[i] + sum2[j]); 
        } 
        for (int i = maxt; i < maxt + M; i++) ans = min(ans, dp[i]); 
        cout << ans << endl; 
        return 0; 
    } 
    
  • 相关阅读:
    再谈应用程序单例运行(只能开启一个进程)
    wpf 无边框窗口 最大化,缩放问题修复
    AutoClose=false的情况下自动关闭下拉框(ToolStripHost)
    C#调用其他语言(如PB)的com组件
    再写Javascript闭包
    Vue 数据双向绑定的误区
    后台数据缓存的一点心得
    C# 使用 Newtonsoft.Json 对DataTable转换中文乱码问题的解决
    第二章 Background & Borders 之 Multiple borders
    第二章 Background & Borders 之 Transparent Border
  • 原文地址:https://www.cnblogs.com/heyujun/p/10004386.html
Copyright © 2011-2022 走看看