CF-[CF1841C] Ranom Numbers 题解
C: Ranom Numbers
C - Ranom Numbers
本题最暴力的方法就是将每一个位置都改变取最大值,此方法是
考虑是否可以只改变几个位置,答案是可以的。
定义:一个字母小是字典序小,大同理。
先给结论:
- 一个字母若要变大,只需要改这个字母最左边的即可。
- 一个字母若要变小,只需要改这个字母最右边的即可。
结论证明:
严谨证明较复杂,不过思路很清晰,只证结论 1 (
证:
就以字母
设中间的字母的最大值为
先证
现在我们只需要知道
为了阅读的方便,以下的“优于”和“更优”都是“不劣于”的意思,除“一定优于”外。
先证
再证如果
最后证
整理上述 4 个证明可知:
代码实现:
-
计算整个字符串的值,从后往前。
-
为了方便,因为已经知道了两条结论,所以直接对 10 个位置进行更换为
A 到E 的暴力修改。
时间复杂度:
核心代码:
const int N = 2e5 + 10;
char str[N];
int ch[5] = {1, 10, 100, 1000, 10000};
int ans, L[5], R[5];
void init(){
ans = -inf;
mms(L, 0), mms(R, 0);
}
int calc(int len){
int res = 0;
char maxc = 'A';
pre(i, len, 1){
int c = str[i] - 'A';
if(maxc > str[i]) res += -ch[c];
else{
maxc = str[i];
res += ch[c];
}
}
return res;
}
int main(){
int T; rd(T);
while(T--){
sf("%s", str + 1);
int len = strlen(str + 1);
init();
rep(i, 1, len){
if(!L[str[i] - 'A']) L[str[i] - 'A'] = i;
R[str[i] - 'A'] = i;
}
rep(i, 0, 4){ //替换前
if(!R[i]) continue; //LR都行
rep(j, 0, 4){ //替换后
//替换L
char temp = str[L[i]];
str[L[i]] = 'A' + j;
ans = max(ans, calc(len));
str[L[i]] = temp;
//替换R
temp = str[R[i]];
str[R[i]] = 'A' + j;
ans = max(ans, calc(len));
str[R[i]] = temp;
}
}
prf("%d\n", ans);
}
return 0;
}
完整代码