PepperLa‘s String

PepperLa’s String

题目链接

题意 :
给一个字符串 s ss,可以删去一个字符,并且可以对其进行任意的压缩表示一个字符加其连续出现次数的十六进制表示,求最短的表示串,相同长度则输出字典序最小的。

思路 :
如果连续出现两个或以上的字符,压缩表示长度更短,如果只有一个,则显然不需要压缩。考虑删去一个字符使得长度减小的情况:① 删去单一字符,长度减一;② 删去两个字符中的一个,长度减一;③ 删去一个字符后,其出现次数位数减少一。从左到右扫描字符串,如果有 ① 情况且字典序能变小,直接停止;否则剩余能减小长度的情况都会增大字典序(除了在结尾处删),则尽可能让删除位置靠右。不能减小长度的情况,则删去第一个字符最优。

在这里插入图片描述

AC代码 :

#include <iostream>
#include <map>
#include <utility>
#include <cstring>
#include <algorithm>
#include <math.h>

#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e6 + 5;
 
string s, ch("0123456789ABCDEF");
struct Node{
    char ch; string v; int cnt;
} a[maxn];
int n, m;
 
string getS(int x){
 
    string s = "";
    while(x > 0){
    
        s += ch[x % 16];
        x /= 16;
    }
    reverse(s.begin(), s.end());
    return s;
};
 
void print(){
 
    for(int i = 0; i < m; ++i){
 
        if(!a[i].cnt) continue;
        else if(a[i].cnt == 1) cout << a[i].ch;
        else cout << a[i].ch << a[i].v;
    }
    cout << "\n";
}
 
void solve(){
 
    int ret = 0;
    for(int i = 0; i < m; ++i){
 
        if(a[i].cnt == 1){
 
            ret = i;
            if(i < m && a[i + 1].ch < a[i].ch) break;
        }
        else if(a[i].cnt == 2) ret = i;
        else if(a[i].v == "1" + string(a[i].v.size() - 1, '0')) ret = i;
    }
    --a[ret].cnt, a[ret].v = getS(a[ret].cnt);
    print();
}
 
int main(){
 
    ios::sync_with_stdio(0); cin.tie(0);
    while(cin >> s){
 
        n = s.size(), m = 0;
        int cnt = 1, flg = 0;
        for(int i = 1; i < n; ++i){
 
            if(s[i] == s[i - 1]) ++cnt;
            else a[m++] = Node{s[i - 1], getS(cnt), cnt}, cnt = 1;
        }
        a[m++] = Node{s[n - 1], getS(cnt), cnt};
        solve();
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值