wannafly day2 Erase Numbers I B

题目链接https://www.zhixincode.com/contest/8/problem/B?problem_id=123

题目大意:总共n个数,删除2个,要使删完之后连起来拼出的数字最大,输出这个连起来的结果

贪心题,直接想情况比较复杂,可以把删两次的过程看做两次独立的删除。

每次独立的删除中,肯定优先删除位数最小的数,再比较所有最小的数删除后剩余的数对答案的贡献,这里只要顺序两两比较最小位数的数删除后的结果。如果删除前面的数结果更优就结束这次删除,反之继续比较。

因为一旦前面的数删除比下一个结果更优,那么肯定在较高位比下一位要高,再往下删除的话,较高位已经定下来了,是没有可能再比前面的结果更优了。

删除l和r的时候 两者的区别只在于:

删L:[L+1,R]

删R:[L,R-1]

只要比较这个区间就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <random>
#include <cstring>
#include <chrono>
#include <cmath>
#include <stdlib.h>
#include <map>
#define LL long long
using namespace std;
const int maxn = 6e3 + 10;
int s[maxn * 10], t[maxn * 10];
int T, n, lenq, vis[maxn], da[maxn], len[maxn], nxt[maxn], lst[maxn];

/*
 * 分两次删除处理,每次删除是一个独立的过程
 * 在一次删除操作中,比较所有当前最短长度删除之后对答案产生的贡献
 * */

void add(int *q, int x)//数组看作是一个整数,ai代表第i位的数
{
    if (x)
    {
        add(q, x / 10);
        q[++lenq] = x % 10;
    }
}

int check(int l, int r)
{
    //(l + 1, r) erase(l)
    //(l, r - 1) erase(r)
    lenq = 0;

    for (int i = l + 1; i <= r; ++i)//删l
    {
        if (!vis[i]) add(s, da[i]);
    }
    lenq = 0;
    for (int i = l; i < r; ++i)//删r
    {
        if (!vis[i]) add(t, da[i]);
    }
    for (int i = 1; i <= lenq; ++i)//比较删除两者的结果
    {
        if (s[i] > t[i]) return 1;
        if (s[i] < t[i]) return 0;
    }
    return 0;
}

void erase()
{
    int Minlen = 1 << 30, num = 0, p = -1;
    for (int i = 1; i <= n; ++i)
    {
        if (vis[i])
        {
            continue;
        }
        Minlen = min(Minlen, len[i]);
    }
    for (int i = 1; i <= n; ++i)
    {
        if (vis[i] || len[i] > Minlen)
        {
            continue;
        }
        //所有最小长度的ai p记录最后一个最小长度的串的位置
        ++num; lst[i] = p; p = i;
    }
    nxt[p] = -1;
    if (num == 1)//只有一个最小长度的串
    {
        vis[p] = 1;
        return;
    }
    while (lst[p] != -1)
    {
        nxt[lst[p]] = p;
        p = lst[p];
    }

    while (nxt[p] != -1)
    {
        if (check(p, nxt[p]))
        {
            vis[p] = 1;
            return ;
        }
        p = nxt[p];
    }
    vis[p] = 1;
}

int main()
{
    cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        cin>>n;
        for (int i = 1; i <= n; ++i)
        {
            vis[i] = 0, len[i] = 0;
        }
        for (int i = 1, x; i <= n; ++i)
        {
            cin>>da[i];
            x = da[i];
            while (x)
            {
                x /= 10;
                ++len[i];//记录ai的位数
            }
        }
        erase(); erase();
        cout<<"Case #"<<kase<<": ";
        for (int i = 1; i <= n; ++i)
        {
            if (!vis[i])
            {
                cout<<da[i];
                //cout<<"sss"<<endl;
            }
        }
        cout<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值