zoukankan      html  css  js  c++  java
  • 题解 门童

    link

    Description

    (n) 个人需要接待,每个人可以被接待的时间为 ([L_i,R_i]),你提前 (j) 分钟接待他的话可以产生 (j imes p_i) 的贡献。可以在门口和沙发之间来回,需要时间为 (L),待在门口或者辗转都会减少贡献,在沙发上会增加贡献。

    问接待完所有人时贡献最大值。(nle 10^5,L_i,R_i,p_ile 10^9)

    Solution

    考场上面sb了。

    可以想到的是,会辗转的时间一定在 (L_i,R_i) ,所以我们可以离散化,然后设 (f_i) 表示第 (i) 个时间在门口的最大贡献。

    我们将需要服务的人按 (L_i) 排序,那么一次一定服务一段合法区间最优。然后你们 (f_i) 就是由 (f_{i-1}) 已经一段区间的 (f_j) 转移而来。dp 式非常好列就不写了。

    然后你发现可以斜优,就做完了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define int long long
    #define MAXN 200005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
    
    int n,m,L,x[2][2],f[MAXN],Ed[MAXN],tmp[MAXN],mpos[MAXN],mxpos[MAXN],pre1[MAXN],pre2[MAXN],Pre1[MAXN],Pre2[MAXN],minn[MAXN][21];
    
    struct node{
    	int st,ed,P;
    	bool operator < (const node &p)const{return st < p.st;}
    }s[MAXN];
    
    void init (){
    	for (Int i = 1;i <= n;++ i) minn[i][0] = s[i].ed;
    	for (Int j = 1;(1 << j) <= n;++ j)
    		for (Int i = 1;i + (1 << j) - 1 <= n;++ i)
    			minn[i][j] = min (minn[i][j - 1],minn[i + (1 << j - 1)][j - 1]);
    }
    
    int query (int l,int r){
    	if (l > r) return 1e18;
    	int k = log2 (r - l + 1);
    	return min (minn[l][k],minn[r - (1 << k) + 1][k]);
    }
    
    int head,tail,sta[MAXN];
    int getb (int j){return f[j] - tmp[j] * x[1][1] - pre1[j];}
    int geta (int j){return pre2[j];}
    int son (int j1,int j2){return getb (j2) - getb (j1);}
    int mot (int j1,int j2){return geta (j2) - geta (j1);}
    
    signed main(){
    //	freopen ("large_2.in","r",stdin);
    //	freopen ("f1.out","w",stdout);
    	read (n,L);
    	for (Int i = 0;i < 2;++ i) for (Int j = 0;j < 2;++ j){
    		read (x[i][j]);
    		if (!i || !j) x[i][j] = -x[i][j];
    	}
    	for (Int i = 1;i <= n;++ i){
    		int st,ed,p;read (st,ed,p);
    		ed += st,s[i] = node{st,ed,p};
    	}
    	sort (s + 1,s + n + 1);
    	for (Int i = 1;i <= n;++ i) Pre1[i] = Pre1[i - 1] + s[i].ed * s[i].P,Pre2[i] = Pre2[i - 1] + s[i].P;
    	for (Int i = 1;i <= n;++ i) tmp[++ m] = s[i].st,tmp[++ m] = s[i].ed;
    	sort (tmp + 1,tmp + m + 1),m = unique (tmp + 1,tmp + m + 1) - tmp - 1;
    	memset (f,0xcf,sizeof (f)),f[0] = 0,init ();
    	for (Int i = 1;i <= m;++ i){
    		int tim = tmp[i];
    		int l = 1,r = n,ans = 0;
    		while (l <= r){
    			int mid = l + r >> 1;
    			if (s[mid].st <= tim) ans = mid,l = mid + 1;
    			else r = mid - 1;
    		}
    		Ed[i] = ans,pre1[i] = Pre1[ans],pre2[i] = Pre2[ans],l = 0,r = i - 1,ans = i;
    		while (l <= r){
    			int mid = l + r >> 1;
    			if (tim <= query (Ed[mid] + 1,Ed[i])) ans = mid,r = mid - 1;
    			else l = mid + 1;
    		}
    		mpos[i] = ans,l = 0,r = i - 1,ans = 0;
    		while (l <= r){
    			int mid = l + r >> 1;
    			if (tmp[i] - tmp[mid] >= 2 * L && Ed[mid] < n) ans = mid,l = mid + 1;
    			else r = mid - 1;
    		}
    		mxpos[i] = ans;
    	}
    	int now = 0;sta[head = tail = 1] = 0;
    	for (Int i = 1;i <= m;++ i){
    		while (now < mxpos[i]){
    			now ++;
    			while (tail - head + 1 >= 2 && son (sta[tail - 1],sta[tail]) * mot (sta[tail],now) <= son (sta[tail],now) * mot (sta[tail - 1],sta[tail])) -- tail;
    			sta[++ tail] = now;
    		}
    		while (head <= tail && sta[head] < mpos[i]) ++ head;
    		if (mpos[i] <= mxpos[i]){
    			while (head < tail && son (sta[head],sta[head + 1]) > -tmp[i] * mot (sta[head],sta[head + 1])) ++ head;
    			if (head <= tail){
    				int j = sta[head];
    				f[i] = getb (j) + geta (j) * tmp[i] + L * (x[0][1] + x[1][0]) + (tmp[i] - 2 * L) * x[1][1] + pre1[i] - tmp[i] * pre2[i];
    			}
    		}
    		chkmax (f[i],f[i - 1] + (tmp[i] - tmp[i - 1]) * x[0][0] + pre1[i] - pre1[i - 1] - tmp[i] * (pre2[i] - pre2[i - 1]));
    	}
    	int res = -1e18;
    	for (Int i = 1;i <= m;++ i) if (Ed[i] == n) chkmax (res,f[i]);
    	write (res),putchar ('
    ');
     	return 0;
    }
    
  • 相关阅读:
    周总结13
    周总结11
    《程序员的自我修养》阅读笔记四
    周总结10
    数据导入hive仓库
    周总结9
    《程序员的自我修养》阅读笔记三
    《软件需求》读书笔记四
    《软件需求》读书笔记三
    《软件需求》读书笔记二
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/15413722.html
Copyright © 2011-2022 走看看