#529. 【美团杯2020】114514【贪心】

题目链接


  题目给出的条件是给出一个长度不超过6e5的串,它一定是由n个“114514”组成的长度为6n的串。114514的顺序一定是按照这个顺序,但是排列可以是错综复杂的,但是保证一定有解。

  一个“114514”中有两个‘4’,这是很关键的,我们可以把原式拆成11(4a)51(4b)这样的形式,4a指的是出现于前面的4,4b指的是出现于后面的4。于是我们想根据(4a)、(4b)确定这个串的组合。

  如果我们确定了4a、4b,那么首先就可以确定5了,从后往前,第i个4a对应第i个4b对应第i个5,于是接下去只需要确定1的位置就可以了。

  这里,我们不妨将1、4作为相互关系的两个信息来进行用以确定4是4a还是4b这样的一个功能。

这里需要满足如下的条件:

  1. 4a前面需要有两个1
  2. 4b前面(4a后面)需要有一个1

  譬如说,有一个后缀,该后缀有x个1以及有y个4,那么,如果x>y了,就说明现在后面有4a了,因为两个1和一个1的关系,所以后面如果有(x - y)个4a,于是剩下(2y - x)个4b,就会使得2y - x + 2 * (x - y) = 2y - x + 2x - 2y = x此时1的条件是可以满足的。

  于是,我们可以确定每一个后缀中的4a的最少的数量,然后同时也可以确定1的位置了。

  因为从贪心的角度来看,在满足上述条件的情况下,4b的前一个1,越靠后越好,所以根据这则信息,我们找到一个4b,就将其前面的一个1给它,而在其后面的但是却没有用掉的1,作为4a的1来进行使用。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 6e5 + 7;
int one[2][maxN], five[maxN], four[2][maxN], top[5];   //'1' '4a' '5' '1' '4b'
char s[maxN];
int N, len, need_a[maxN] = {0}, suff[maxN][2] = {0};
signed main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        memset(top, 0, sizeof(top));
        scanf("%s", s + 1);
        len = (int)strlen(s + 1);
        N = len / 6;
        suff[len + 1][0] = suff[len + 1][1] = 0;
        for(int i=len; i>=0; i--)
        {
            suff[i][0] = suff[i + 1][0];    //'1'
            suff[i][1] = suff[i + 1][1];    //'4'
            if(s[i] == '1')
            {
                suff[i][0]++;
            }
            else if(s[i] == '4')
            {
                suff[i][1]++;
            }
            need_a[i] = max(0, suff[i][0] - suff[i][1]);
        }
        for(int i=0; i<=len; i++) need_a[i + 1] = max(need_a[i + 1], need_a[i] - (s[i] == '4'));
        int pos = len;
//        for(int i=1; i<=len; i++) printf("%d%c", need_a[i], i == len ? '\n' : ' ');
        for(int i=len, have_a = 0; i>=1; i--)
        {
            if(s[i] == '4')
            {
                if(have_a < need_a[i])
                {
                    four[0][++top[1]] = i;
                    have_a++;
                }
                else
                {
                    four[1][++top[4]] = i;
                    while(pos >= i)
                    {
                        if(s[pos] == '1') one[0][++top[0]] = pos;
                        pos--;
                    }
                    while(s[pos] != '1') pos--;
                    one[1][++top[3]] = pos;
                    pos--;
                }
            }
            else if(s[i] == '5')
            {
                five[++top[2]] = i;
            }
        }
        while(pos >= 1)
        {
            if(s[pos] == '1') one[0][++top[0]] = pos;
            pos--;
        }
        for(int i=N; i>=1; i--) printf("%d %d %d %d %d %d\n", one[0][(i << 1)], one[0][(i << 1) - 1], four[0][i], five[i], one[1][i], four[1][i]);
    }
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值