zoukankan      html  css  js  c++  java
  • [AcWing303/304]任务安排2/3

    [AcWing303]任务安排2

    (N) 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 (N) 个任务分成若干批,每一批包含连续的若干个任务。从时刻 (0) 开始,任务被分批加工,执行第 (i) 个任务所需的时间是 (t[i]) 。另外,在每批任务开始前,机器需要 (S) 的启动时间,故执行一批任务所需的时间是启动时间 (S) 加上每个任务所需时间之和。一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 (c[i]) 。请为机器规划一个分组方案,使得总费用最小。

    (1≤N≤3∗10^5)
    (1≤S,Ti,Ci≤512)

    (T[i]) 为时间的前缀和 , (C[i]) 是系数 (c) 的前缀和 . 在一批任务开始对后续任务产生影响时,就先把费用累加到答案中. 这就是"费用提前计算"的思想 .
    对于每一次转移, 有 (chkmin(f[i], f[j] + (C[j] - C[i]) * T[i] + S * (C[n] - C[j])))

    考虑到数据范围很像斜率优化 , 把式子转化为斜率优化的形式 :

    (f[j] = (S + T[i]) * C[j] - S * C[n] - T[i] * C[i] + f[i])

    发现斜率是固定的 , 当截距最小时 (f[i]) 最小 . 所以要维护 ((C[j],f[j])) 围成的下凸包 .

    由于 (f[j])(C[j]) 单调递增 , ((S+T[i])) 也是单调递增的 , 所以可以用单调队列维护 : 只保留两点间斜率 (>=S+T[i]) 的点 , 入队时检查有没有斜率递增

    时间复杂度 (O(n))

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define Debug(x) cout<<#x<<"="<<x<<endl
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7;
    inline LL read(){
        register LL x=0,f=1;register char c=getchar();
        while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
        while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
        return f*x;
    }
    
    const int N = 3e5 + 5;
    
    int T[N], C[N], q[N], f[N];
    int n, S;
    
    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();
    	}
    	int l = 1, r = 1;
    	q[1] = 0; // 把0入队是因为j取0是合法的.
    	for(int i = 1; i <= n; ++i){
    		while(l < r && ((f[q[l+1]] - f[q[l]]) <= (S + T[i]) * (C[q[l+1]] - C[q[l]]))) l++;
    		f[i] = f[q[l]] - (T[i] + S) * C[q[l]] + C[i] * T[i] + S * C[n];
    		while(l < r && ((f[q[r]] - f[q[r-1]]) * (C[q[i]] - C[q[r]]) >= (f[q[i]] - f[q[r]]) * (C[q[r]] - C[q[r-1]]))) r--;
    		q[++r] = i;
    	}
    	printf("%d
    ", f[n]);
    }
    

    [AcWing304]任务安排3

    (1≤N≤3∗10^5 ; 0≤S,c[i]≤512 ; -512≤t[i]≤512)

    完成的时间可以为负数 , 则 (S+T[i]) 不再具有单调性 . 所以在单调队列中二分查找出对应的位置 , 不需要出队 , 但需要维护入队时的斜率单调性

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define Debug(x) cout<<#x<<"="<<x<<endl
    #define int long long
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7;
    inline LL read(){
        register LL x=0,f=1;register char c=getchar();
        while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
        while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
        return f*x;
    }
    
    const int N = 3e5 + 5;
    
    int f[N], q[N], T[N], C[N];
    int n, S;
    
    inline int find(int L, int R, int x){
    	while(L < R){
    		int mid = (L + R) >> 1;
    		if((f[q[mid+1]] - f[q[mid]]) <= x * (C[q[mid+1]] - C[q[mid]])) L = mid + 1; ///
    		else R = mid;
    	}
    	return L;
    }
    
    signed main(){
    	n = read(), S = read();
    	for(int i = 1; i <= n; ++i){
    		T[i] = T[i-1] + read();
    		C[i] = C[i-1] + read();
    	}
    	int l = 1, r = 1;
    	for(int i = 1; i <= n; ++i){
    		int p = find(l, r, S + T[i]);
    		f[i] = f[q[p]] - (S + T[i]) * C[q[p]] + S * C[n] + T[i] * C[i];
    		while(l < r && ((f[q[r]] - f[q[r-1]]) * (C[i] - C[q[r]]) >= (f[i] - f[q[r]]) * (C[q[r]] - C[q[r-1]]))) r--;
    		q[++r] = i;
    	}
    	printf("%lld
    ", f[n]);
    }
    
  • 相关阅读:
    Android 在一个程序中启动另一个程序
    Android SDK Manager国内无法更新的解决方案
    Android studio 安装中遇到一些问题的解决办法,分享一下
    apache服务器伪静态配置说明
    POJ3253 Fence Repair【贪心】
    洛谷P1090 合并果子【贪心】
    POJ3069 Saruman's Army【贪心】
    洛谷P1012 拼数【字符串+排序】
    POJ3617 Best Cow Line【贪心】
    洛谷P1583 魔法照片【模拟+排序】
  • 原文地址:https://www.cnblogs.com/lizehon/p/11198836.html
Copyright © 2011-2022 走看看