zoukankan      html  css  js  c++  java
  • 【日常训练】【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;
    }
    
  • 相关阅读:
    【leetcode】299. 猜数字游戏
    【leetcode】300. 最长递增子序列
    【leetcode】223. 矩形面积
    【leetcode】222. 完全二叉树的节点个数
    【leetcode】229. 求众数 II
    【leetcode】215. 数组中的第K个最大元素
    【leetcode】221. 最大正方形
    【leetcode】216. 组合总和 III
    【leetcode】213. 打家劫舍 II
    【leetcode】210. 课程表 II
  • 原文地址:https://www.cnblogs.com/czyarl/p/13044004.html
Copyright © 2011-2022 走看看