zoukankan      html  css  js  c++  java
  • Codeforces Round #518 (Div. 1) Computer Game 倍增+矩阵快速幂

    接近于死亡的选手没有水平更博客,所以现在每五个月更一篇。

    这道题呢,首先如果已经有权限升级了,那么后面肯定全部选的是 (p_ib_i) 最高的。

    设这个值为 (M=max limits_i p_ib_i)

    主要的问题在于前面怎么选。

    假设剩下的时间还有 (t) 秒。那么我们很容易得到一个这样的式子。

    [dp[t+1] = max_i {p_i cdot (a_i+tM) + (1-p_i) cdot dp[t]} ]

    (max)里面的内容整理一下。

    [dp[t+1] = dp[t] + max_i{p_icdot(tM - dp[t]) + a_ip_i} ]

    如果 (i) 确定了,那么 (max) 里面的东西就是一个关于 (tM-dp[t]) 的一次函数。

    而把一堆一次函数取 (max) 显然可以通过维护这些一次函数的凸包,然后在凸包上二分 (tM-dp[t]) 的位置解决。

    但是这样做的时间复杂度为 (O((n+t)log n))

    可巧我们有一个显然的结论就是 (dp[t+1]-dp[t] < M)

    那么就是说 (tM-dp[t] < (t+1)M -dp[t+1])。也就是说,需要在凸包上走的东西是单调递增的。

    由于凸包不超过 (n) 段,所以可以在每一段上做矩阵快速幂。

    [egin{bmatrix} 1-p_i & p_iM & a_ip_i\ 0 & 1 & 1\ 0 & 0 & 1 end{bmatrix} cdot egin{bmatrix} dp[t]\ t\ 1 end{bmatrix} = egin{bmatrix} dp[t+1]\ t+1\ 1 end{bmatrix} ]

    直接二分是 (O(n(log n + log^2t))) 的。可以使用倍增,(O(n(log n+log t)))

    #include<bits/stdc++.h>
    using namespace std;
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I>
    inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 1e5 + 7;
    const int LOG = 36;
    const double eps = 1e-13;
    
    int n, nl;
    ll t;
    double M;
    int a[N], b[N], q[N];
    double p[N];
    
    inline int dcmp(const double &x) { return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1); }
    struct Line {
    	double k, b;
    	inline bool operator < (const Line &a) const { return dcmp(k - a.k) < 0 || (dcmp(k - a.k) == 0 && b < a.b); }
    //	inline bool operator < (const Line &a) const { return b > a.b; }
    } l[N];
    
    inline double crs(const Line &l1, const Line &l2) { return (l2.b - l1.b) / (l1.k - l2.k); }
    
    struct Matrix {
    	double a[3][3];
    	inline Matrix() { memset(a, 0, sizeof(a)); }
    	inline Matrix(const double &x) {
    		memset(a, 0, sizeof(a));
    		a[0][0] = a[1][1] = a[2][2] = x;
    	}
    	
    	inline void print() {
    		for (int i = 0; i < 3; ++i) {
    			for (int j = 0; j < 3; ++j)
    				dbg("%.13lf ", a[i][j]);
    			puts("");
    		}
    	}
    	
    	inline Matrix operator * (const Matrix &b) {
    		Matrix c;
    		c.a[0][0] = a[0][0] * b.a[0][0] + a[0][1] * b.a[1][0] + a[0][2] * b.a[2][0];
    		c.a[0][1] = a[0][0] * b.a[0][1] + a[0][1] * b.a[1][1] + a[0][2] * b.a[2][1];
    		c.a[0][2] = a[0][0] * b.a[0][2] + a[0][1] * b.a[1][2] + a[0][2] * b.a[2][2];
    		c.a[1][0] = a[1][0] * b.a[0][0] + a[1][1] * b.a[1][0] + a[1][2] * b.a[2][0];
    		c.a[1][1] = a[1][0] * b.a[0][1] + a[1][1] * b.a[1][1] + a[1][2] * b.a[2][1];
    		c.a[1][2] = a[1][0] * b.a[0][2] + a[1][1] * b.a[1][2] + a[1][2] * b.a[2][2];
    		c.a[2][0] = a[2][0] * b.a[0][0] + a[2][1] * b.a[1][0] + a[2][2] * b.a[2][0];
    		c.a[2][1] = a[2][0] * b.a[0][1] + a[2][1] * b.a[1][1] + a[2][2] * b.a[2][1];
    		c.a[2][2] = a[2][0] * b.a[0][2] + a[2][1] * b.a[1][2] + a[2][2] * b.a[2][2];
    		return c;
    	}
    } f[LOG];
    
    inline void ycl() {
    	for (int i = 1; i <= n; ++i) smax(M, p[i] * b[i]), l[i] = (Line){ p[i], p[i] * a[i] };
    	sort(l + 1, l + n + 1);
    	for (int i = 1; i <= n; ++i) if (dcmp(l[i].k - l[nl].k)) l[++nl] = l[i]; else l[nl] = l[i];
    	n = nl, nl = 1;
    	q[1] = 1;
    	for (int i = 2; i <= n; ++i) {
    //		if (dcmp(crs(l[q[nl]], l[i])) <= 0) continue;
    		while (nl > 1 && dcmp(crs(l[q[nl - 1]], l[i]) - crs(l[q[nl - 1]], l[q[nl]])) <= 0) --nl;
    		q[++nl] = i;
    	}
    	for (int i = 1; i <= nl; ++i) l[i] = l[q[i]];//, dbg("Line : %.13lf %.13lf
    ", l[i].k, l[i].b);
    	n = nl;
    //	for (int i = 1; i <= n; ++i) dbg("Line : %.13lf %.13lf
    ", l[i].k, l[i].b);
    //	dbg("%.13lf %.13lf
    ", crs(l[1], l[4]), crs(l[1], l[3]));
    }
    
    inline void work() {
    	ycl();
    	
    	double dp = 0;
    	ll tt = 0;
    	for (int i = 1; i <= n && tt < t; ++i) {
    		double stp;
    		if (i < n) stp = crs(l[i], l[i + 1]);
    		else stp = 1e20;
    		
    		if (tt < t && dcmp(tt * M - dp - stp) >= 0) continue;
    		
    		Matrix A, B;
    		A.a[0][0] = dp, A.a[1][0] = tt, A.a[2][0] = 1;
    		B.a[0][0] = 1 - l[i].k, B.a[0][1] = l[i].k * M, B.a[0][2] = l[i].b;
    		B.a[1][1] = 1, B.a[1][2] = 1;
    		B.a[2][2] = 1;
    		f[0] = B;
    		for (int i = 1; i < LOG; ++i) f[i] = f[i - 1] * f[i - 1];
    		
    		for (int i = LOG - 1; ~i; --i) if (tt + (1ll << i) < t) {
    			Matrix C = f[i] * A;
    //			if (i == 1) C.print();
    			if (dcmp(C.a[1][0] * M - C.a[0][0] - stp) < 0) A = C, tt += 1ll << i;
    		}
    		A = f[0] * A, ++tt;
    		dp = A.a[0][0];
    	}
    	printf("%.13lf
    ", dp);
    }
    
    inline void init() {
    	read(n), read(t);
    	for (int i = 1; i <= n; ++i) read(a[i]), read(b[i]), scanf("%lf", &p[i]);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    记忆力训练今天早上有了点小进步
    刻意练习
    12.12周计划
    12.6周总结
    The Power of Reading Insights
    Storytelling with Data
    nexus私服和快照正式版本etc
    springboot启动流程分析
    容器启动getBean的流程分析
    canal简介
  • 原文地址:https://www.cnblogs.com/hankeke/p/CF1067D.html
Copyright © 2011-2022 走看看