Codeforces1422E Minlexes
题目链接
题目大意
给定一个字符串 \(S\)
对于 \(S\) 的每一个后缀 \(suf\) ,你可以删除任意对相邻的字符
问 \(S\) 的每个 \(suf\) 在删除了任意对相邻的字符后最小字典序是多少
解题思路
从前往后显然是不好做的,因为后一个 \(suf\) 和前一个 \(suf\) 是不一样的,所以前一个\(suf\) 的信息无法传递给后一个 \(suf\)
考虑从后往前做,那么前一个 \(suf\) 是包含后一个 \(suf\) 的,可以将后一个 \(suf\) 的信息转移给前一个,可行
从后往前贪心,定义字符串 \(pre1\) 记录后一个后缀,\(pre2\) 记录后两个后缀
若 \(si = s_{i+1}\) , 判断 \(s_i + pre1\) 与 \(pre2\) 的大小关系
如果 $s_i + pre1 > pre2 $ 选择不删除 , \(ans = pre1 + si\)
否则删除 \(s_i\) 和 \(s_{i+1}\) , \(ans = pre2\)
否则 \(ans = si + pre1\)
判断 \(s_i + pre1\) 与 \(pre2\) 的大小关系只要判断从 \({i+2} → n\) 第一个不等于 \(si\) 的字符与 \(si\) 的大小关系即可
AC_Code
#include<bits/stdc++.h>
#define rep(i , a , b) for(int i = a ; i <= b ; i ++)
#define per(i , b , a) for(int i = b ; i >= a ; i --)
using namespace std;
stack<pair<int , string>>ans;
int cnt1[30] , cnt2[30] , cnt[30];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
string s;
cin >> s;
int n = s.size() , m = 1;
string pre1 = string(1 , s[n - 1]) , pre2 = "";
char ma1 = s[n - 1] , ma2 = ' ';
ans.push(make_pair(1 , pre1));
rep(j , 0 , 25) cnt1[j] = -1 , cnt2[j] = -1;
rep(j , 0 , 25) if(s[n - 1] - 'a' != j) cnt1[j] = s[n - 1] - 'a';
per(i , n - 2 , 0)
{
string res = "";
int flag = 0;
if(s[i] == s[i + 1])
{
int x = cnt1[s[i] - 'a'];
if(x < s[i] - 'a') res = pre2 , flag = 2;
else res = s[i] + pre1 , flag = 1;
}
else res = s[i] + pre1 , flag = 1;
if(flag == 2) rep(j , 0 , 25) swap(cnt1[j] , cnt2[j]);
else rep(j , 0 , 25)
{
cnt2[j] = cnt1[j];
if(j != s[i] - 'a') cnt1[j] = s[i] - 'a';
}
int m = res.size();
if(m <= 10) ans.push(make_pair(m , res));
else
{
string ha = res.substr(0 , 5);
ha += "...";
ha += string(1 , res[m - 2]) + string(1 , res[m - 1]);
ans.push(make_pair(m , ha));
}
pre2 = pre1;
pre1 = res;
}
while(!ans.empty()) cout << ans.top().first << " " << ans.top().second << '\n' , ans.pop();
return 0;
}
凡所不能将我击倒的,都将使我更加强大