[队内测试Day10.26][P97]T1 字符串+前缀和

大意:

给定一字符串,定义权值为串中出现次数最多字符 - 出现次数最少字符,求权值最大子串
字符串长度 n <= 10^6,保证都由小写字母组成

考完试悔的肠子都青了的题……
明明离正解那么近了……

考场思路:
发现求区间l,r中字符a出现次数-字符b出现次数,用前缀和可以表示为

SraSla(SrbSlb)

SraSrb(SlaSlb)

而我们发现, min(SaSb) 是可以被维护的……
又因为扫描到某一位置时,作为最多字符更新目前最优答案的只可能是该位置上的字符
所以每一位置for一遍26个字符,寻找可能作为最小值的字符

还有问题……
虽然维护了 min(SaSb) ,并且可以保证该位置出现在当前位置之前
但不一定该位置与当前位置组成的区间里存在字符b
对此的处理方法:记录b最后出现的位置和 min(SaSb) 的位置
因为注意到 min(SaSb) 的性质,是只有在 Sb 更新时才会增加的
所以 min(SaSb) 的位置一定为b存在的位置
如果 Posmin(SaSb)=PosLastb ,就让答案强行 - -,表示b + 1

%%%考场正解的summer && wyh

后来wyh讲了更直观的思路
“要suma和sumb的差值最大,就减去sumb比suma多的最多的区间”
ssssrO

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
char s[1000010];
int n;
int sum[30],mnum[30][30],mpos[30][30];
int last[1000010];
int ans;
int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d",&n);
    scanf("%s",s + 1);
    memset(last,-1,sizeof(last));
    for(int i = 1;i <= n;i ++){
        int t = s[i] - 'a';
        sum[t] ++;
        last[t] = i;
        for(int k = 0;k <= 25;k ++){
            if(k == t)continue;
            if(mnum[k][t] > sum[k] - sum[t])
                mnum[k][t] = sum[k] - sum[t],mpos[k][t] = i;
        }
        for(int k = 0;k <= 25;k ++){
            if(k == t || !sum[k])continue;
            int tmp = sum[t] - sum[k] - mnum[t][k];
            if(mpos[t][k] == last[k])tmp --;
            ans = max(ans,tmp);
        }
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

明明有思路的题放着不打,自己去T2找恶心……
但后来检查考场代码思路确实凌乱……

Tips:
用适当的变量名代替表达式使代码更简洁
对自己的思路有信心……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值