【日常训练】【CF】20200604_金币_CF377E_简单dp/斜率优化

题面

题解

现场得分:100/100

我竟然现场写对斜率优化了!

  • 我们发现一定是始终在用v最大的工厂。我们的每一步的新工厂一定是c和v都比前一个大的。
  • 于是我们可以按照v先排个序,再处理一下,把所有存在其他工厂比自己v大,c小的那些废物工厂扔掉。
  • 我们还能发现,买下第(i)个工厂之后,我以后的时刻的金币数一定是一个斜率为(v_i)的直线。
  • 我们就有了一个(O(n^2))的dp,记(f_i)表示买下了第(i)的工厂,得到的直线截距最大是多少。
  • 转移显然。
  • 我这里都说是直线了,显然可以斜率优化。

代码

#include<bits/stdc++.h>
#define LL long long
#define MAXN 200100
#define INF 10000000000000000
using namespace std;
template<typename T>void Read(T &cn)
{
	char c; int sig = 1;
	while(!isdigit(c = getchar())) if(c == '-') sig = -1; cn = c-48;
	while(isdigit(c = getchar())) cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
	if(cn < 0) {putchar('-'); cn = 0-cn; }
	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
	while(cn) wei++, cm = cm*10+cn%10, cn/=10;
	while(wei--) putchar(cm%10+48), cm /= 10;
	putchar(cx+48);
}
template<typename T>void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T>void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
struct qwe{
	LL v,c;
	void getit() {Read(v); Read(c); }
	inline friend bool operator <(qwe a, qwe b) {return a.v == b.v ? a.c > b.c : a.v < b.v; }
};
struct xian{
	LL k, b;
	LL suan(LL cn) {return (cn - b+k-1)/k; }
	void mk(LL cn, LL cm) {k = cn; b = cm; }
};
qwe a[MAXN+1];
int n;
LL m;
int xu[MAXN+1], xlen;
LL f[MAXN+1], g[MAXN+1];

xian zhan[MAXN+1];
int l, r;
int jiao_z(LL cn, xian A, xian B) {return cn*(A.k - B.k) <= (B.b - A.b); }
int jiao(xian A, xian B, xian C) 
{
	double db1 = (B.b-A.b), db2 = (C.b-B.b);
	double dk1 = (A.k-B.k), dk2 = (B.k-C.k);
	return db1*dk2 >= db2*dk1; 
}
LL qiu(int cn, int cm) 
{
	while(l < r && jiao_z(zhan[l].suan(cn), zhan[l], zhan[l+1])) l++;
	if(l > r) return -INF;
	return -zhan[l].suan(cn)*(cm-zhan[l].k) - cn + zhan[l].b;
}
void zeng(int ck, LL cb)
{
	xian lin; lin.mk(ck, cb);
	while(l < r && jiao(zhan[r-1], zhan[r], lin)) r--; 
	zhan[++r] = lin;
}
int main()
{
//	freopen("collect.in","r",stdin);
//	freopen("collect.out","w",stdout);
	Read(n); Read(m);
	for(int i = 1;i<=n;i++) a[i].getit();
	sort(a+1, a+n+1); xlen = 0;
	for(int i = 1;i<=n;i++) 
	{
		if(a[i].v <= 0) continue;
		while(xlen && a[xu[xlen]].c > a[i].c) xlen--; 
		xu[++xlen] = i; 
	}
	for(int i = 1;i<=xlen;i++) a[i] = a[xu[i]];
	n = xlen;
	f[0] = 0; a[0].v = a[0].c = 0;
	l = 1; r = 0; f[1] = 0;
	zeng(a[1].v, f[1]);
	LL ans = (m + a[1].v-1)/a[1].v;
	for(int i = 2;i<=n;i++)
	{
		f[i] = qiu(a[i].c, a[i].v);
		zeng(a[i].v, f[i]);
		Min(ans, (m - f[i] + a[i].v-1)/a[i].v);
	}
	Write(ans); puts("");
	return 0;
}
原文地址:https://www.cnblogs.com/czyarl/p/13044004.html