分析
其实本题中蕴含一个重要结论:最佳情况是最多考虑10个位置来替换:A的第一个和最后一个位置,B的第一个或最后一个位置,依此类推。
这样,我们只有50个不同的候选答案(10个位置每个位置可以替换成5个字母中的任意一个),我们可以在O(n)中检查它们中的每一个。
证明:当我们替换一个字符时,我们要么增加它,要么减少它。如果我们增加一个字符,很容易看出为什么只尝试每个字符第一次出现的位置即可——增加一个字符可能会影响它左边的一些字符(将它们从正转为负),不会影响右边的字符。通过选择一个字符第一次出现的位置,我们确保从正到负转换的字符数量尽可能少。注意,如果字符串至少有一个不同于E的字符,我们可以将第一个这样的字符替换为E,并将答案增加至少9000(这在证明的第二部分中很有用)。
现在假设减少一个字符是最优的,让我们展示一下,选择最后一个出现的字符来减少总是最优的。(将最后一个字符减少,比如把最后一个E减少,不会影响其右边的字符,只会影响其左边有一部分字符,即倒数第二个E和最后一个E之间的某些字符,使其权值由负转正。)假设我们减少了一个字符,而这不
是最后一次出现的位置。(如果修改的不是最后一个字符,则其左边和右边的其它字符都不会受到影响,只有该字符本身的权值会发生变化。)这意味着该字符在替换后将为负数,因此在替换之前应该为负数(这样对答案的影响尽可能小)。通过用另一个负数字符替换负数字符,我们可以为答案添加的最大值是999(对应将负数的D更改为负数的A),我们已经证明,通过用E替换字符串中的第一个非E字符,我们至少可以让答案增加9000。因此,如果我们减少一个字符,而它不是该字符的最后一次出现的位置,则这必定不是最优的。
所以,我们只要正反各做一次,记录每一个字符第一次出现(反着相当于最后一次),然后统计分数就行。
另外两种思路
上代码
贪心
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int t,pos[11],ap[6],sum,ans;
int main()
{
cin>>t;
while(t--)
{
int sum=0,ans=-2147483600;
string a;
cin>>a;
int len=a.length();
for(int i=0;i<=len-1;i++)
{
if(a[i]=='A'&&ap[1]==0) pos[1]=i,ap[1]=1;
else if(a[i]=='B'&&ap[2]==0) pos[2]=i,ap[2]=1;
else if(a[i]=='C'&&ap[3]==0) pos[3]=i,ap[3]=1;
else if(a[i]=='D'&&ap[4]==0) pos[4]=i,ap[4]=1;
else if(a[i]=='E'&&ap[5]==0) pos[5]=i,ap[5]=1;
}
memset(ap,0,sizeof(ap));
for(int i=len-1;i>=0;i--)
{
if(a[i]=='A'&&ap[1]==0) pos[6]=i,ap[1]=1;
else if(a[i]=='B'&&ap[2]==0) pos[7]=i,ap[2]=1;
else if(a[i]=='C'&&ap[3]==0) pos[8]=i,ap[3]=1;
else if(a[i]=='D'&&ap[4]==0) pos[9]=i,ap[4]=1;
else if(a[i]=='E'&&ap[5]==0) pos[10]=i,ap[5]=1;
}
memset(ap,0,sizeof(ap));
char mx='0';
for(int i=len-1;i>=0;i--)
{
if(a[i]>=mx)
{
mx=a[i];
if(a[i]=='A') sum+=1;
else if(a[i]=='B') sum+=10;
else if(a[i]=='C') sum+=100;
else if(a[i]=='D') sum+=1000;
else if(a[i]=='E') sum+=10000;
}
else
{
if(a[i]=='A') sum-=1;
else if(a[i]=='B') sum-=10;
else if(a[i]=='C') sum-=100;
else if(a[i]=='D') sum-=1000;
else if(a[i]=='E') sum-=10000;
}
}
ans=max(sum,ans);
for(int k=1;k<=10;k++)
{
for(int j=1;j<=5;j++)
{
sum=0;mx='0';
for(int i=len-1;i>=0;i--)
{
char t;
if(pos[k]==i) t=char(j+64);
else t=a[i];
if(t>=mx)
{
mx=t;
if(t=='A') sum+=1;
else if(t=='B') sum+=10;
else if(t=='C') sum+=100;
else if(t=='D') sum+=1000;
else if(t=='E') sum+=10000;
}
else
{
if(t=='A') sum-=1;
else if(t=='B') sum-=10;
else if(t=='C') sum-=100;
else if(t=='D') sum-=1000;
else if(t=='E') sum-=10000;
}
}
ans=max(ans,sum);
}
}
cout<<ans<<endl;
}
return 0;
}