题目描述:
已知一个长度为n的由小写字母组成的字符串,求一个子串,出现最多的字母出现的个数减去该段中出现过的出现次数最少的字母出现的个数最大。求这个个数。
题目分析:
-
法一:
枚举是哪两种字母相减,设为a,b,那么就只需要把a,b从原串中拿出来,a的值+1,b的值-1,求最大子段和,虽然a,b并不一定是真实串中最多最少的字母,但是这样做的最大值一定是答案。每个位置最多拿出来52次,复杂度是 O ( 52 n ) O(52n) O(52n)注意求最大子段和时必须保证串中既有a又有b,即当 [ l , r ] [l,r] [l,r]中 l l l位置的字符为b时才能用存下来的最小值去更新使用的最小值,相当于延迟更新。
-
法二:
DP,设 s u m [ i ] [ j ] sum[i][j] sum[i][j]表示前 i i i个字符中字符 j j j的出现次数,那么 a n s = max ( s u m [ r ] [ i ] − s u m [ l − 1 ] [ i ] − ( s u m [ r ] [ j ] − s u m [ l − 1 ] [ j ] ) ) = max ( s u m [ r ] [ i ] − s u m [ r ] [ j ] − ( s u m [ l − 1 ] [ i ] − s u m [ l − 1 ] [ j ] ) ) ans=\max \big(sum[r][i]-sum[l-1][i]-(sum[r][j]-sum[l-1][j])\big)\\=\max \big(sum[r][i]-sum[r][j]-(sum[l-1][i]-sum[l-1][j])\big) ans=max(sum[r][i]−sum[l−1][i]−(sum[r][j]−sum[l−1][j]))=max(sum[r][i]−sum[r][j]−(sum[l−1][i]−sum[l−1][j]))
考虑 r − 1 r-1 r−1变为 r r r,r位置的字符为 p p p,记 f [ i ] [ j ] = s u m [ r ] [ i ] − s u m [ r ] [ j ] f[i][j]=sum[r][i]-sum[r][j] f[i][j]=sum[r][i]−sum[r][j],同法一的延迟更新类似,此时存下的 f [ j ] [ p ] f[j][p] f[j][p]的最小值可以用来更新 m i n [ j ] [ p ] min[j][p] min[j][p]。然后只有 f [ p ] [ j ] f[p][j] f[p][j]和 f [ j ] [ p ] f[j][p] f[j][p]会变。然后更新对应的答案即可。
法一Code:
#include<bits/stdc++.h>
#define maxn 1000005
#define LL long long
using namespace std;
const int inf = 1<<30;
int n,ans;
char c[maxn];
vector<int>pos[26];
void solve(int i,int j){
int sum=0,mn=inf,rmn=0;
for(int x=0,y=0;x<pos[i].size()||y<pos[j].size();){
if(y==pos[j].size()||(x<pos[i].size()&&pos[i][x]<pos[j][y])) sum++,x++;
else sum--,mn=min(mn,rmn),y++;
rmn=min(rmn,sum);
if(mn!=inf) ans=max(ans,sum-mn);
}
}
int main()
{
scanf("%d%s",&n,c+1);
for(int i=1;i<=n;i++) pos[c[i]-'a'].push_back(i);
for(int i=0;i<26;i++) for(int j=0;j<26;j++) if(i!=j) solve(i,j);
printf("%d\n",ans);
}
法二Code:
#include<bits/stdc++.h>
#define maxn 1000005
#define LL long long
using namespace std;
const int inf = 1<<30;
int n,mn[26][26],rmn[26][26],sum[26][26],ans;
char c[maxn];
int main()
{
memset(mn,0x3f,sizeof mn);
scanf("%d%s",&n,c+1);
for(int i=1;i<=n;i++){
int p=c[i]-'a';
for(int j=0;j<26;j++) if(j!=p){
sum[p][j]++,sum[j][p]--;
mn[j][p]=min(mn[j][p],rmn[j][p]);
rmn[j][p]=min(rmn[j][p],sum[j][p]);
ans=max(ans,sum[p][j]-mn[p][j]);
ans=max(ans,sum[j][p]-mn[j][p]);
}
}
printf("%d\n",ans);
}