• bzoj2726 [SDOI2012]任务安排


    题目链接

    problem

    机器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。

    solution

    f[i]表示前i个物品进行分组的最小花费。
    下面的(c_i)表示题目描述中(c_i)的前缀和,(t_i)表示题目描述中(t_i)的前缀和。

    考虑(n^2)做法

    由于每次分组都会导致后面的时刻后移,所以花费系数就是(c_n-c_j)

    (f_i=min{f_j+(c_n-c_j)(t_i-t_j+S)},jin[0,i))

    (n^2)转移即可。

    考虑优化成(nlogn)

    将上面的式子展开并处理一下:

    (f_i=min{f_j+c_nt_i-c_nt_j+c_nS-c_jt_i+c_jt_j-c_jS}\ =min{t_i(c_n-c_j)+f_j-c_nt_j+c_nS+c_jt_j-c_jS})

    然后就很斜率优化了。。

    可是(t_i)并没有单调性

    所以不能直接单调队列优化。可以用一个单调栈维护凸包,然后查询的时候就在上面二分即可。

    code

    /*
    * @Author: wxyww
    * @Date:   2019-12-17 19:59:58
    * @Last Modified time: 2019-12-17 21:13:05
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 300100;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1; c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0'; c = getchar();
    	}
    	return x * f;
    }
    ll c[N],t[N],n;
    ll S;
    
    struct node {
    	ll k,b;
    }q[N];
    
    int top;
    
    void ins(ll k,ll b) {
    	while(top >= 1) {
    		ll k2 =  q[top].k,k3 = q[top - 1].k,b2 = q[top].b,b3 = q[top - 1].b;
    		if((b2 - b) * (k2 - k3) <= (b3 - b2) * (k - k2)) --top;
    		else break;
    	}
    	q[++top] = (node){k,b};
    }
    inline ll calc(ll k,ll b,ll x) {
    	return k * x + b;
    }
    ll get(ll x) {
    	int l = 1,r = top;
    	int ans = 0;
    	while(l <= r) {
    		int mid = (l + r) >> 1;
    		if(calc(q[mid].k,q[mid].b,x) > calc(q[mid - 1].k,q[mid - 1].b,x)) r = mid - 1;
    		else ans = mid,l = mid + 1;
    	}
    	return calc(q[ans].k,q[ans].b,x);
    }
    
    int main() {
    	n = read(),S = read();
    	for(int i = 1;i <= n;++i) {
    		t[i] = t[i - 1] + read();c[i] = c[i - 1] + read();
    	}
    	q[0].k = c[n],q[0].b = S * c[n];
    	ins(c[n],S * c[n]);
    	ll now = 0;
    	for(int i = 1;i <= n;++i) {
    		now = get(t[i]);
    		ins(c[n] - c[i],now + c[i] * t[i] - c[n] * t[i] + S * (c[n] - c[i]));
    	}
    	cout<<now;
    	return 0;
    }
    
  • 相关阅读:
    分片副本监控优化备份分词器03
    es score限制
    German Collegiate Programming Contest 2017 G. Water Testing
    SQL注入以及sqlmap初体验
    BUUCTF [极客大挑战 2019]Upload 1
    DVWA—File Upload 文件上传
    DVWA—XSS 跨站脚本攻击
    WUSTCTF2020 佛说:只能四天
    猪圈密码
    2016全国大学生信息安全竞赛 破译
  • 原文地址:https://www.cnblogs.com/wxyww/p/bzoj2726.html
Copyright © 2020-2023  润新知