codeforces 1480 D1 Painting the Array I (贪心)

题面

在这里插入图片描述

题意

把一个长度为n的数组分成两个子数组a,b,要求seg(a)+seg(b) 最大 ,seg(a)表示数组中不同的连续段,例如[1,1,2,2,3,3,3,1] 连续段就是[1,2,3,1] 长度是4

题解

  1. 我们采用贪心的思想考虑,假设v1是数组a的末尾元素,v2是数组b的末尾元素,我们依次遍历原数组中的元素,然后考虑放在a后还是b后是最优解
  2. 如果v1==v2 ,a[i]放在哪里都一样,贡献值是0/1 ,如果v1 != v2, 如果是v1 == a[i] , a[i]放在v1后贡献值是0,放在v2后的贡献值是1,贪心考虑局部最优解,肯定就是放在v2后边了,然后更新v2,v1!=a[i] ,v2 == a[i] 也是一样的道理
  3. 还有一种情况就是v1,v2,a[i] 都不相同 ,那么a[i] 是否可以任意放,肯定是不行的,我们举个例子,假设现在v1=1,v2=2,剩余数组[3,2,2] ,那么3就不能随便放,因为3如果放在1后边,接下来第二个2放在哪里贡献值都为0,对于这种情况,我们就要看下一个1出现的位置和下一个2出现的位置,显然2出现的位置要更早一些,那么3就应该放在2后边来防止相同的数字出现减小贡献值具体看代码

代码

#include<bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;

int n, a[N], id[N];
vector<int> v[N];

int main() {

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        v[a[i]].push_back(i);
    }
    int res = 0;
    int v1 = -1, v2 = -1;
    for (int i = 1; i <= n; i++) {
        id[a[i]]++;
        if (v1 == v2) {
            if (v1 != a[i]) {
                v1 = a[i];
                res++;
            }
        } else if (v1 == a[i] && v2 != a[i]) {
            v2 = a[i];
            res++;
        } else if (v1 != a[i] && v2 == a[i]) {
            v1 = a[i];
            res++;
        } else {
            if (v1 == -1) v2 = a[i], res++;
            else if (v2 == -1) v1 = a[i], res++;
            else {
                int next_v1 = n + 1, next_v2 = n + 1;
                if (id[v1] < v[v1].size()) next_v1 = v[v1][id[v1]];
                if (id[v2] < v[v2].size()) next_v2 = v[v2][id[v2]];
                if (next_v1 < next_v2) v1 = a[i], res++;
                else v2 = a[i], res++;
            }
        }

    }
    cout << res << endl;

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值