zoukankan      html  css  js  c++  java
  • ABC218H Red and Blue Lamps

    ABC218H Red and Blue Lamps

    题意

    (N)个位置染色,如果(A_i)(A_{i+1})不同色,则获得(a_i) ,要求涂(r)个红色,(n-r)个蓝色

    [N leq 2e5 ]

    分析

    显然会选择贪心地涂间隔(r)个颜色(r leq n /2)

    问题转化为从(n)个物品中选取(r)个不相邻物品使得总价值最大

    直接朴素的令(dp[i][j])表示前(i)个物品选择(j)个的做法复杂度很难下降

    WQS二分可以把这样的问题转化为任意选择物品个数下的最大价值

    (g(x))表示选择(x)个物品的最大价值,显然这是一个凸函数 ,凸函数的性质就是切线斜率具有单调性。

    1.二分斜率

    对这个凸包的斜率进行二分,如果能通过二分得到点(x),就可以比较(x)和已知的限制(r)来偏移二分的区间

    2.计算截距

    对于一个固定的斜率,想要寻找和它切的点,只需要找到和(y)轴截距最大的点(画个图可以明白)

    亦即(f(x)= g(x) - kx) 只需要求出(f_{max})即可,考察这个函数的意义:就是每选择一个物品,总价值减(k) 下的最大价值,这个东西就是个简单DP

    这样就能记录取到(f_{max})时的(x)

    3. 把二分得到的值再把斜率加回去

    然后就做完了,注意实数

    代码

    #include<bits/stdc++.h>
    #define pii pair<long long,long long>
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef vector<int> VI;
    
    
    inline ll rd(){
        ll x;
        scanf("%lld",&x);
        return x;
    }
    
    /*
    inline int rd(){
    	int x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x;
    }*/
    
    const int MOD = 23333333;
    
    inline int mul(int a,int b){
        int res = (ll)a * b % MOD;
        if(res < 0) res += MOD;
        return res;
    }
    
    inline void add(int &a,int b){
        a += b;
        if(a >= MOD) a -= MOD;
    }
    
    inline void sub(int &a,int b){
        a -= b;
        if(a < 0) a += MOD;
    }
    
    
    ll gcd(ll a,ll b){
    	return !b ? a : gcd(b,a % b);
    }
    
    const int maxn = 2e5 + 5;
    
    int n,r;
    int a[maxn];
    
    pair<long double,int> dp[maxn][2];
    
    pair<long double,int> check(long double v){
    	dp[n + 1][0] = dp[n + 1][1] = make_pair(0,0);
    	for(int i = n;i >= 1;i--){
    		for(int j = 0;j < 2;j++){
    			auto r0 = dp[i + 1][0],r1 = dp[i + 1][1];
    			if(!j) r1.fi += a[i];
    			else r0.fi += a[i];
    			dp[i][j] = max(r0,r1);
    			if(!j) 
    				dp[i][j].se++,dp[i][j].fi -= v;
    		}
    	}
    	return max(dp[1][0],dp[1][1]);
    }
    
    
    int main(){
    	n = rd();
    	r = rd();
    	for(int i = 1;i <= n - 1;i++)
    		a[i] = rd();
    	long double L = -1e15,R = 1e15;
    	for(int i = 0;i < 100;i++){
    		long double mid = (L + R) / 2.0;
    		auto it = check(mid);
    		if(it.se < r) R = mid;
    		else L = mid;
    	}
    	auto it = check(L);
    	ll ans = (ll)(it.fi + r * L);
    	printf("%lld",ans);	
    }
    
  • 相关阅读:
    315,谁来保护手游开发者的利益
    微信小程序之提高应用速度小技巧
    Python-爬虫-Beautifulsoup解析
    Python-爬虫-requests
    Python-form表单标签
    设计模式のTemplatePattern(模板模式)----行为模式
    链接
    python入门007
    007作业
    005作业
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15260091.html
Copyright © 2011-2022 走看看