Codeforces1480D1 D2. Painting the Array I(II)

31 篇文章 0 订阅
18 篇文章 0 订阅

D1. Painting the Array I

题意:

本题与 CF1480D2 的唯一区别是本题询问最大可能解.

给定一个数组 a a a, 你将将 a i a_i ai染为 b i b_i bi色, 其中 b b b 是由你指定的一个 01 数组. 将 a a a 数组中被染成 0 色的数字取出来并依在 a a a 中出现的顺序排列, 组成数组 a ( 0 ) a^{(0)} a(0). 同理, 将 a a a 数组中被染成 1 色的数字取出来并依在 a a a 中出现的顺序排列, 组成数组 a ( 1 ) a^{(1)} a(1). 我们定义 s e g ( c ) seg(c) seg(c)是一个正整数, 其中 c c c 是一个数组, s e g ( c ) seg(c) seg(c)的值为在我们将 c c c 中相邻的所有相同元素合并后, c c c 数组的大小. 例如, s e g ( [ 1 , 1 , 4 , 5 , 1 , 4 ] ) = ∣ [ 1 , 4 , 5 , 1 , 4 ] ∣ = 5 seg([1, 1, 4, 5, 1, 4]) = |[1, 4, 5, 1, 4]|=5 seg([1,1,4,5,1,4])=[1,4,5,1,4]=5. 最大化 s e g ( a ( 0 ) ) seg(a^{(0)}) seg(a(0))+ s e g ( a ( 1 ) ) seg(a^{(1)}) seg(a(1))

思路:

我们看这个题,就是让你将这个串分成两部分x,y,两部分内部合并,贪心的想。

  1. 如果当前字符与 x x x, y y y末尾至少一个相等,那么当前字符肯定加到末尾不与当前字符相等的地方,这样这个字符就不会被合并。
  2. 都不相等。我们将 当前字符 加入 x x x 当且仅当 n e x t ( x ) < n e x t ( y ) next(x)<next(y) next(x)<next(y)。其中 next(x)next(x) 表示 x x x 这种值下一次出现的位置,若之后没有出现 n e x t ( x ) = n + 1 next(x)=n+1 next(x)=n+1

这个后缀转移指针很好 写这个题全因为这个知识点。
具体就是贪心的想,离他越近越危险,就将他加到离危险最远的地方。

代码:

void solve()
{
    cin >> n;
    x = 0, y = 0;
    sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", &a[i]);
        b[i] = n + 1;
    }

    for(int i = n; i >= 1; i--)
    {
        c[i] = b[a[i]];
        b[a[i]] = i;
    }
    a[0] = 0;
    ll l=n+1,r=n+1;
    for(int i = 1; i <= n; i++)
    {
        if(a[i] == a[s1[x]] && a[i] == a[s2[y]])
        {
            l=c[i];
            continue;
        }
        else if(a[i] == a[s1[x]])
        {
            sum++;
            s2[++y] = i;
            r=c[i];
        }
        else if(a[i] == a[s2[y]])
        {
            sum++;
            s1[++x] = i;
            l=c[i];
        }
        else
        {
            sum++;
            if(l< r)
            {
                s1[++x] = i;
                l=c[i];
            }
            else
            {
                s2[++y] = i;
                r=c[i];
            }
        }
    }
    cout << sum << endl;
}

D2. Painting the Array II

题意:

本题与 CF1480D1 的唯一区别是本题询问最小可能解.

给定一个数组 a a a, 你将将 a i a_i ai染为 b i b_i bi色, 其中 b b b 是由你指定的一个 01 数组. 将 a a a 数组中被染成 0 色的数字取出来并依在 a a a 中出现的顺序排列, 组成数组 a ( 0 ) a^{(0)} a(0). 同理, 将 a a a 数组中被染成 1 色的数字取出来并依在 a a a 中出现的顺序排列, 组成数组 a ( 1 ) a^{(1)} a(1). 我们定义 s e g ( c ) seg(c) seg(c)是一个正整数, 其中 c c c 是一个数组, s e g ( c ) seg(c) seg(c)的值为在我们将 c c c 中相邻的所有相同元素合并后, c c c 数组的大小. 例如, s e g ( [ 1 , 1 , 4 , 5 , 1 , 4 ] ) = ∣ [ 1 , 4 , 5 , 1 , 4 ] ∣ = 5 seg([1, 1, 4, 5, 1, 4]) = |[1, 4, 5, 1, 4]|=5 seg([1,1,4,5,1,4])=[1,4,5,1,4]=5. 最小化 s e g ( a ( 0 ) ) seg(a^{(0)}) seg(a(0))+ s e g ( a ( 1 ) ) seg(a^{(1)}) seg(a(1))

思路:

这个与D1差距就是一个求最长一个求最短。
那么我们可以直接反向最优即可 就是:

  1. 有相同的,直接加后面,不算入价值。
  2. 没有相等的,放到离危险最远的地方。

代码 :

void solve()
{
    cin >> n;
    x = 0, y = 0;
    sum = 0;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", &a[i]);
        b[i] = n + 1;
    }

    for(int i = n; i >= 1; i--)
    {
        c[i] = b[a[i]];
        b[a[i]] = i;
    }
    a[0] = 0;
    ll l = n + 1, r = n + 1;
    for(int i = 1; i <= n; i++)
    {
        if(a[i] == a[s1[x]] && a[i] == a[s2[y]])
        {
            l = c[i];
            continue;
        }
        else if(a[i] == a[s2[y]])
        {
            s2[++y] = i;
            r = c[i];
        }
        else if(a[i] == a[s1[x]])
        {
            s1[++x] = i;
            l = c[i];
        }
        else
        {
            sum++;
            if(l > r)
            {
                s1[++x] = i;
                l = c[i];
            }
            else
            {
                s2[++y] = i;
                r = c[i];
            }
        }
    }
    cout << sum << endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值