zoukankan      html  css  js  c++  java
  • 「题解」Codeforces 442C Artem and Array

    考虑三个相邻的元素 (x,y,z) 满足 (yleq x,z),则三者先删除 (y)​ 更优。

    假设最左侧和最右侧有两个不能删除的 (0),发现和原问题等价,这样就不需要讨论边界情况了。

    考虑反证,不失一般性假设先删除 (x).对于任意一种先删除 (x) 的策略,在删除 (x) 的时候先删除 (y) 一定不劣:

    假设现在序列是 (...,v,x,y,z,...)

    • 如果先删除 (x),对答案贡献是 (min(v,y)),剩余序列为 (...,v,y,z,...)
    • 如果先删除 (y),对答案贡献是 (min(x,z)),剩余序列为 (...,v,x,z,...)

    注意到 (min(v,y)leq yleq min(x,z)),以及序列中的数越大答案越大,所以后者相比前者不劣。

    然后变成双调的,答案为 (n-2) 小的数的和。虽然前面编出来证明了,这里的构造还是w23c3c3教我的/ll

    性质:最大值和次大值一定不会对答案做贡献,所以它们具体取值对答案无所谓,存在的意义仅为比其他所有的都大。

    充分:给出一种构造,如果第三大值在最大值旁边,则删去最大值,否则第三大值在次大值旁边,删去次大值,递归成子问题。

    必要:尝试构造,发现一个数如果对答案贡献 (x) 次,那么一定有一个比它大的数少贡献 ((x-1)) 次,所以每个数仅贡献一次最优。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<set>
    #define pb emplace_back
    #define mp std::make_pair
    #define fi first
    #define se second
    typedef long long ll;
    typedef long double ld;
    typedef std::pair<int, int> pii;
    typedef std::pair<ll, int> pli;
    typedef std::pair<ll, ll> pll;
    typedef std::vector<int> vi;
    typedef std::vector<pii> vpii;
    typedef std::vector<ll> vll;
    const ll mod = 998244353;
    ll Add(ll x, ll y) { return (x+y>=mod) ? (x+y-mod) : (x+y); }
    ll Mul(ll x, ll y) { return x * y % mod; }
    ll Mod(ll x) { return x < 0 ? (x + mod) : (x >= mod ? (x-mod) : x); }
    ll cadd(ll &x, ll y) { return x = (x+y>=mod) ? (x+y-mod) : (x+y); }
    template <typename T> T Max(T x, T y) { return x > y ? x : y; }
    template <typename T> T Min(T x, T y) { return x < y ? x : y; }
    template <typename T>
    T &read(T &r) {
    	r = 0; bool w = 0; char ch = getchar();
    	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    	while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    	return r = w ? -r : r;
    }
    const int N = 500010;
    int n, a[N], l[N], r[N], vis[N], b[N], mx, bmx;
    ll ans;
    std::queue<int>q;
    bool check(int x) {
    	return x && !vis[x] && a[x] <= a[l[x]] && a[x] <= a[r[x]];
    }
    signed main() {
    	read(n);
    	for(int i = 1; i <= n; ++i) read(a[i]), l[i] = i-1, r[i] = i+1; r[n] = 0;
    	for(int i = 2; i < n; ++i)
    		if(check(i))
    			q.push(i), vis[i] = 1;
    	while(!q.empty()) {
    		int x = q.front(); q.pop();
    		ans += Min(a[l[x]], a[r[x]]);
    		r[l[x]] = r[x]; l[r[x]] = l[x];
    		if(check(l[x])) q.push(l[x]), vis[l[x]] = 1;
    		if(check(r[x])) q.push(r[x]), vis[r[x]] = 1;
    	}
    	for(int i = 1; i <= n; ++i)
    		if(!vis[i]) {
    			ans += a[i];
    			if(a[i] >= mx) bmx = mx, mx = a[i];
    			else bmx = Max(bmx, a[i]);
    		}
    	printf("%lld
    ", ans-mx-bmx);
    	return 0;
    }
    
  • 相关阅读:
    Andriod开发环境配置
    Java调用WebService
    Message Modem Develop
    Call .so in Linux
    How to unpack a tar file in windows
    Visual Studio 2010工程目录下的ipch文件夹和.sdf文件
    TWAIN学习记录
    几种调用扫描仪的方案
    Gzip Practice
    Twain Practice
  • 原文地址:https://www.cnblogs.com/do-while-true/p/15437168.html
Copyright © 2011-2022 走看看