• uoj233/BZOJ4654/洛谷P1721 [Noi2016]国王饮水记 【dp + 斜率优化】


    题目链接

    uoj233

    题解

    下面不加证明地给出几个性质:

    1. 小于(h[1])的城市一定是没用的
    2. 任何城市联通包含(1)且只和(1)联通一次
    3. 联通顺序从小到大最优
    4. 单个联通比多个一起联通要优
    5. 最优解中多个一起联通不超过(14)

    除了最后一个外还是很显然的
    (K)足够大肯定逐个联通,否则有一些还是需要一起联通的
    我们可以设(f[i][j])表示前(i)个城市,联通(j)(h[1])的最高高度
    那么,去掉小于(h[1])的城市,将(h[i])排序,记(s[i])(h[i])前缀和

    [f[i][j] = max{frac{f[k][j - 1] + s[i] - s[k]}{i - k + 1}} ]

    可以斜率优化且具有决策单调性
    又由于最多不超过(14)次多个联通,所以找到(14)次中最优决策之后剩余的就可以逐个联通了
    复杂度(O(np))

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    // ---------- decimal lib start ----------
    const int PREC = 3000;
    class Decimal {
    	public:
    		Decimal();
    		Decimal(const std::string &s);
    		Decimal(const char *s);
    		Decimal(int x);
    		Decimal(long long x);
    		Decimal(double x);
    		
    		bool is_zero() const;
    		
    		// p (p > 0) is the number of digits after the decimal point
    		std::string to_string(int p) const;
    		double to_double() const;
    		
    		friend Decimal operator + (const Decimal &a, const Decimal &b);
    		friend Decimal operator + (const Decimal &a, int x);
    		friend Decimal operator + (int x, const Decimal &a);
    		friend Decimal operator + (const Decimal &a, long long x);
    		friend Decimal operator + (long long x, const Decimal &a);
    		friend Decimal operator + (const Decimal &a, double x);
    		friend Decimal operator + (double x, const Decimal &a);
    		
    		friend Decimal operator - (const Decimal &a, const Decimal &b);
    		friend Decimal operator - (const Decimal &a, int x);
    		friend Decimal operator - (int x, const Decimal &a);
    		friend Decimal operator - (const Decimal &a, long long x);
    		friend Decimal operator - (long long x, const Decimal &a);
    		friend Decimal operator - (const Decimal &a, double x);
    		friend Decimal operator - (double x, const Decimal &a);
    		
    		friend Decimal operator * (const Decimal &a, int x);
    		friend Decimal operator * (int x, const Decimal &a);
    		
    		friend Decimal operator / (const Decimal &a, int x);
    		
    		friend bool operator < (const Decimal &a, const Decimal &b);
    		friend bool operator > (const Decimal &a, const Decimal &b);
    		friend bool operator <= (const Decimal &a, const Decimal &b);
    		friend bool operator >= (const Decimal &a, const Decimal &b);
    		friend bool operator == (const Decimal &a, const Decimal &b);
    		friend bool operator != (const Decimal &a, const Decimal &b);
    		
    		Decimal & operator += (int x);
    		Decimal & operator += (long long x);
    		Decimal & operator += (double x);
    		Decimal & operator += (const Decimal &b);
    		
    		Decimal & operator -= (int x);
    		Decimal & operator -= (long long x);
    		Decimal & operator -= (double x);
    		Decimal & operator -= (const Decimal &b);
    		
    		Decimal & operator *= (int x);
    		
    		Decimal & operator /= (int x);
    		
    		friend Decimal operator - (const Decimal &a);
    		
    		// These can't be called
    		friend Decimal operator * (const Decimal &a, double x);
    		friend Decimal operator * (double x, const Decimal &a);
    		friend Decimal operator / (const Decimal &a, double x);
    		Decimal & operator *= (double x);
    		Decimal & operator /= (double x);
    		
    	private:
    		static const int len = PREC / 9 + 1;
    		static const int mo = 1000000000;
    		
    		static void append_to_string(std::string &s, long long x);
    		
    		bool is_neg;
    		long long integer;
    		int data[len];
    		
    		void init_zero();
    		void init(const char *s);
    };
    
    Decimal::Decimal() {
    	this->init_zero();
    }
    
    Decimal::Decimal(const char *s) {
    	this->init(s);
    }
    
    Decimal::Decimal(const std::string &s) {
    	this->init(s.c_str());
    }
    
    Decimal::Decimal(int x) {
    	this->init_zero();
    	
    	if (x < 0) {
    		is_neg = true;
    		x = -x;
    	}
    	
    	integer = x;
    }
    
    Decimal::Decimal(long long x) {
    	this->init_zero();
    	
    	if (x < 0) {
    		is_neg = true;
    		x = -x;
    	}
    	
    	integer = x;
    }
    
    Decimal::Decimal(double x) {
    	this->init_zero();
    	
    	if (x < 0) {
    		is_neg = true;
    		x = -x;
    	}
    	
    	integer = (long long)x;
    	x -= integer;
    	
    	for (int i = 0; i < len; i++) {
    		x *= mo;
    		if (x < 0) x = 0;
    		data[i] = (int)x;
    		x -= data[i];
    	}
    }
    
    void Decimal::init_zero() {
    	is_neg = false;
    	integer = 0;
    	memset(data, 0, len * sizeof(int));
    }
    
    bool Decimal::is_zero() const {
    	if (integer) return false;
    	for (int i = 0; i < len; i++) {
    		if (data[i]) return false;
    	}
    	return true;
    }
    
    void Decimal::init(const char *s) {
    	this->init_zero();
    	
    	is_neg = false;
    	integer = 0;
    	
    	// find the first digit or the negative sign
    	while (*s != 0) {
    		if (*s == '-') {
    			is_neg = true;
    			++s;
    			break;
    		} else if (*s >= 48 && *s <= 57) {
    			break;
    		}
    		++s;
    	}
    	
    	// read the integer part
    	while (*s >= 48 && *s <= 57) {
    		integer = integer * 10 + *s - 48;
    		++s;
    	}
    	
    	// read the decimal part
    	if (*s == '.') {
    		int pos = 0;
    		int x = mo / 10;
    		
    		++s;
    		while (pos < len && *s >= 48 && *s <= 57) {
    			data[pos] += (*s - 48) * x;
    			++s;
    			x /= 10;
    			if (x == 0) {
    				++pos;
    				x = mo / 10;
    			}
    		}
    	}
    }
    
    void Decimal::append_to_string(std::string &s, long long x) {
    	if (x == 0) {
    		s.append(1, 48);
    		return;
    	}
    	
    	char _[30];
    	int cnt = 0;
    	while (x) {
    		_[cnt++] = x % 10;
    		x /= 10;
    	}
    	while (cnt--) {
    		s.append(1, _[cnt] + 48);
    	}
    }
    
    std::string Decimal::to_string(int p) const {
    	std::string ret;
    	
    	if (is_neg && !this->is_zero()) {
    		ret = "-";
    	}
    	
    	append_to_string(ret, this->integer);
    	
    	ret.append(1, '.');
    	
    	for (int i = 0; i < len; i++) {
    		// append data[i] as "%09d"
    		int x = mo / 10;
    		int tmp = data[i];
    		while (x) {
    			ret.append(1, 48 + tmp / x);
    			tmp %= x;
    			x /= 10;
    			if (--p == 0) {
    				break;
    			}
    		}
    		if (p == 0) break;
    	}
    	
    	if (p > 0) {
    		ret.append(p, '0');
    	}
    	
    	return ret;
    }
    
    double Decimal::to_double() const {
    	double ret = integer;
    	
    	double k = 1.0;
    	for (int i = 0; i < len; i++) {
    		k /= mo;
    		ret += k * data[i];
    	}
    	
    	if (is_neg) {
    		ret = -ret;
    	}
    	
    	return ret;
    }
    
    bool operator < (const Decimal &a, const Decimal &b) {
    	if (a.is_neg != b.is_neg) {
    		return a.is_neg && (!a.is_zero() || !b.is_zero());
    	} else if (!a.is_neg) {
    		// a, b >= 0
    		if (a.integer != b.integer) {
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] < b.data[i];
    			}
    		}
    		return false;
    	} else {
    		// a, b <= 0
    		if (a.integer != b.integer) {
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] > b.data[i];
    			}
    		}
    		return false;
    	}
    }
    
    bool operator > (const Decimal &a, const Decimal &b) {
    	if (a.is_neg != b.is_neg) {
    		return !a.is_neg && (!a.is_zero() || !b.is_zero());
    	} else if (!a.is_neg) {
    		// a, b >= 0
    		if (a.integer != b.integer) {
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] > b.data[i];
    			}
    		}
    		return false;
    	} else {
    		// a, b <= 0
    		if (a.integer != b.integer) {
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] < b.data[i];
    			}
    		}
    		return false;
    	}
    }
    
    bool operator <= (const Decimal &a, const Decimal &b) {
    	if (a.is_neg != b.is_neg) {
    		return a.is_neg || (a.is_zero() && b.is_zero());
    	} else if (!a.is_neg) {
    		// a, b >= 0
    		if (a.integer != b.integer) {
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] < b.data[i];
    			}
    		}
    		return true;
    	} else {
    		// a, b <= 0
    		if (a.integer != b.integer) {
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] > b.data[i];
    			}
    		}
    		return true;
    	}
    }
    
    bool operator >= (const Decimal &a, const Decimal &b) {
    	if (a.is_neg != b.is_neg) {
    		return !a.is_neg || (a.is_zero() && b.is_zero());
    	} else if (!a.is_neg) {
    		// a, b >= 0
    		if (a.integer != b.integer) {
    			return a.integer > b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] > b.data[i];
    			}
    		}
    		return true;
    	} else {
    		// a, b <= 0
    		if (a.integer != b.integer) {
    			return a.integer < b.integer;
    		}
    		for (int i = 0; i < Decimal::len; i++) {
    			if (a.data[i] != b.data[i]) {
    				return a.data[i] < b.data[i];
    			}
    		}
    		return true;
    	}
    }
    
    bool operator == (const Decimal &a, const Decimal &b) {
    	if (a.is_zero() && b.is_zero()) return true;
    	if (a.is_neg != b.is_neg) return false;
    	if (a.integer != b.integer) return false;
    	for (int i = 0; i < Decimal::len; i++) {
    		if (a.data[i] != b.data[i]) return false;
    	}
    	return true;
    }
    
    bool operator != (const Decimal &a, const Decimal &b) {
    	return !(a == b);
    }
    
    Decimal & Decimal::operator += (long long x) {
    	if (!is_neg) {
    		if (integer + x >= 0) {
    			integer += x;
    		} else {
    			bool last = false;
    			for (int i = len - 1; i >= 0; i--) {
    				if (last || data[i]) {
    					data[i] = mo - data[i] - last;
    					last = true;
    				} else {
    					last = false;
    				}
    			}
    			integer = -x - integer - last;
    			is_neg = true;
    		}
    	} else {
    		if (integer - x >= 0) {
    			integer -= x;
    		} else {
    			bool last = false;
    			for (int i = len - 1; i >= 0; i--) {
    				if (last || data[i]) {
    					data[i] = mo - data[i] - last;
    					last = true;
    				} else {
    					last = false;
    				}
    			}
    			integer = x - integer - last;
    			is_neg = false;
    		}
    	}
    	return *this;
    }
    
    Decimal & Decimal::operator += (int x) {
    	return *this += (long long)x;
    }
    
    Decimal & Decimal::operator -= (int x) {
    	return *this += (long long)-x;
    }
    
    Decimal & Decimal::operator -= (long long x) {
    	return *this += -x;
    }
    
    Decimal & Decimal::operator /= (int x) {
    	if (x < 0) {
    		is_neg ^= 1;
    		x = -x;
    	}
    	
    	int last = integer % x;
    	integer /= x;
    	
    	for (int i = 0; i < len; i++) {
    		long long tmp = 1LL * last * mo + data[i];
    		data[i] = tmp / x;
    		last = tmp - 1LL * data[i] * x;
    	}
    	
    	if (is_neg && integer == 0) {
    		int i;
    		for (i = 0; i < len; i++) {
    			if (data[i] != 0) {
    				break;
    			}
    		}
    		if (i == len) {
    			is_neg = false;
    		}
    	}
    	
    	return *this;
    }
    
    Decimal & Decimal::operator *= (int x) {
    	if (x < 0) {
    		is_neg ^= 1;
    		x = -x;
    	} else if (x == 0) {
    		init_zero();
    		return *this;
    	}
    	
    	int last = 0;
    	for (int i = len - 1; i >= 0; i--) {
    		long long tmp = 1LL * data[i] * x + last;
    		last = tmp / mo;
    		data[i] = tmp - 1LL * last * mo;
    	}
    	integer = integer * x + last;
    	
    	return *this;
    }
    
    Decimal operator - (const Decimal &a) {
    	Decimal ret = a;
    	// -0 = 0
    	if (!ret.is_neg && ret.integer == 0) {
    		int i;
    		for (i = 0; i < Decimal::len; i++) {
    			if (ret.data[i] != 0) break;
    		}
    		if (i < Decimal::len) {
    			ret.is_neg = true;
    		}
    	} else {
    		ret.is_neg ^= 1;
    	}
    	return ret;
    }
    
    Decimal operator + (const Decimal &a, int x) {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (int x, const Decimal &a) {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (const Decimal &a, long long x) {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator + (long long x, const Decimal &a) {
    	Decimal ret = a;
    	return ret += x;
    }
    
    Decimal operator - (const Decimal &a, int x) {
    	Decimal ret = a;
    	return ret -= x;
    }
    
    Decimal operator - (int x, const Decimal &a) {
    	return -(a - x);
    }
    
    Decimal operator - (const Decimal &a, long long x) {
    	Decimal ret = a;
    	return ret -= x;
    }
    
    Decimal operator - (long long x, const Decimal &a) {
    	return -(a - x);
    }
    
    Decimal operator * (const Decimal &a, int x) {
    	Decimal ret = a;
    	return ret *= x;
    }
    
    Decimal operator * (int x, const Decimal &a) {
    	Decimal ret = a;
    	return ret *= x;
    }
    
    Decimal operator / (const Decimal &a, int x) {
    	Decimal ret = a;
    	return ret /= x;
    }
    
    Decimal operator + (const Decimal &a, const Decimal &b) {
    	if (a.is_neg == b.is_neg) {
    		Decimal ret = a;
    		bool last = false;
    		for (int i = Decimal::len - 1; i >= 0; i--) {
    			ret.data[i] += b.data[i] + last;
    			if (ret.data[i] >= Decimal::mo) {
    				ret.data[i] -= Decimal::mo;
    				last = true;
    			} else {
    				last = false;
    			}
    		}
    		ret.integer += b.integer + last;
    		return ret;
    	} else if (!a.is_neg) {
    		// a - |b|
    		return a - -b;
    	} else {
    		// b - |a|
    		return b - -a;
    	}
    }
    
    Decimal operator - (const Decimal &a, const Decimal &b) {
    	if (!a.is_neg && !b.is_neg) {
    		if (a >= b) {
    			Decimal ret = a;
    			bool last = false;
    			for (int i = Decimal::len - 1; i >= 0; i--) {
    				ret.data[i] -= b.data[i] + last;
    				if (ret.data[i] < 0) {
    					ret.data[i] += Decimal::mo;
    					last = true;
    				} else {
    					last = false;
    				}
    			}
    			ret.integer -= b.integer + last;
    			return ret;
    		} else {
    			Decimal ret = b;
    			bool last = false;
    			for (int i = Decimal::len - 1; i >= 0; i--) {
    				ret.data[i] -= a.data[i] + last;
    				if (ret.data[i] < 0) {
    					ret.data[i] += Decimal::mo;
    					last = true;
    				} else {
    					last = false;
    				}
    			}
    			ret.integer -= a.integer + last;
    			ret.is_neg = true;
    			return ret;
    		}
    	} else if (a.is_neg && b.is_neg) {
    		// a - b = (-b) - (-a)
    		return -b - -a;
    	} else if (a.is_neg) {
    		// -|a| - b
    		return -(-a + b);
    	} else {
    		// a - -|b|
    		return a + -b;
    	}
    }
    
    Decimal operator + (const Decimal &a, double x) {
    	return a + Decimal(x);
    }
    
    Decimal operator + (double x, const Decimal &a) {
    	return Decimal(x) + a;
    }
    
    Decimal operator - (const Decimal &a, double x) {
    	return a - Decimal(x);
    }
    
    Decimal operator - (double x, const Decimal &a) {
    	return Decimal(x) - a;
    }
    
    Decimal & Decimal::operator += (double x) {
    	*this = *this + Decimal(x);
    	return *this;
    }
    
    Decimal & Decimal::operator -= (double x) {
    	*this = *this - Decimal(x);
    	return *this;
    }
    
    Decimal & Decimal::operator += (const Decimal &b) {
    	*this = *this + b;
    	return *this;
    }
    
    Decimal & Decimal::operator -= (const Decimal &b) {
    	*this = *this - b;
    	return *this;
    }
    
    // ---------- decimal lib end ----------
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
    	return flag ? out : -out;
    }
    const int maxn = 8005;
    Decimal ans;
    int n,K,P,tot,h[maxn],pre[maxn][15],S[maxn];
    int q[maxn],head,tail;
    double f[maxn][15];
    struct point{double x,y;}p[maxn];
    double slope(const point& a,const point& b){
    	return (a.y - b.y) /(a.x - b.x);
    }
    Decimal calc(int i,int j){
    	if (!j) return h[1];
    	return (calc(pre[i][j],j - 1) + S[i] - S[pre[i][j]]) / (i - pre[i][j] + 1);
    }
    int main(){
    	//freopen("1.in","r",stdin);
    	//freopen("1.out","w",stdout);
    	n = read(); K = read(); P = read(); h[tot = 1] = read();
    	for (int i = 2; i <= n; i++){
    		h[i] = read();
    		if (h[i] > h[1]) h[++tot] = h[i];
    	}
    	n = tot; sort(h + 1,h + 1 + n);
    	for (int i = 1; i <= n; i++) S[i] = S[i - 1] + h[i];
    	K = min(n,K);
    	int E = min(K,14);
    	for (int i = 1; i <= n; i++) f[i][0] = h[1];
    	for (int j = 1; j <= E; j++){
    		f[1][j] = h[1];
    		q[head = tail = 1] = 1;
    		for (int i = 1; i <= n; i++) p[i] = (point){i - 1,S[i] - f[i][j - 1]};
    		for (int i = 2; i <= n; i++){
    			point u = (point){i,S[i]};
    			while (head < tail && slope(u,p[q[head]]) < slope(u,p[q[head + 1]])) head++;
    			pre[i][j] = q[head];
    			int v = q[head];
    			f[i][j] = (f[v][j - 1] + S[i] - S[v]) / (i - v + 1);
    			while (head < tail && slope(p[i],p[q[tail]]) < slope(p[q[tail - 1]],p[q[tail]])) tail--;
    			q[++tail] = i;
    		}
    	}
    	int m = n - K + E;
    	double mx = 0; int pos;
    	for (int i = 0; i <= E; i++)
    		if (f[m][i] > mx) mx = f[m][i],pos = m;
    	ans = calc(pos,E);
    	for (int i = pos + 1; i <= n; i++)
    		ans = (ans + h[i]) / 2;
    	cout << ans.to_string(P << 1) << endl;
    	return 0;
    }
    
    
  • 相关阅读:
    maven打包
    &#40;和&#41;后台解析
    beetl简单阅览
    snmp在win10上安装使用
    javaMail发送邮件
    mysql 安装配置详解
    vsftpd的主配置文件详解
    linux下vi命令笔记
    linux下sed命令笔记
    linux下grep命令笔记
  • 原文地址:https://www.cnblogs.com/Mychael/p/9305315.html
Copyright © 2020-2023  润新知