zoukankan      html  css  js  c++  java
  • 洛谷 3519 && bzoj 2213 Difference

    联考考试考到了这个题,随机化40分,现在来秒掉它吧。

    题意:

    给一个字符串,求其中的一段,使得出现次数最多的字符与出现次数最少的字符的出现次数之差最大。

    输入输出样例

    输入样例#1: 复制
    10
    aabbaaabab
    输出样例#1: 复制
    3

    我们定义$cnt[i][j]$表示区间$[1,i]$中,j出现的次数,

    定义字符a,b(非字符a,b),a为出现最多的字符,b为出现最少的字符。

    我们利用前缀和统计每一个字符出现的次数。

    那么对于一个区间$[i,j]$,字符a出现的次数为$cnt[j][a]-cnt[i][a]$,字符b出现的次数为$cnt[j][b]-cnt[i][b]$,我们枚举每一个字符的配对情况。

    对于26个字符$$ans=max { ans,(cnt[j][a]-cnt[i][a])-(cnt[j][b]-cnt[i][b]) }$$。

    这样枚举时间复杂度$O(n^2 imes 26 imes 26)$,还可以啦。

    现在我们来优化一下上边的过程。

    $$(cnt[j][a]-cnt[i][a])-cnt[j][b]-(cnt[i][b])$$

    可以变为

    $$(cnt[j][a]-cnt[j][b])-(cnt[i][a]-cnt[i][b])$$

    对于算式的前半边O(n imes 26)枚举,我们来优化一下后半边。

    对于后边的式子,求得为j以前$cnt[i][a]-cnt[i][b]$的最小值,然而j是怎么过来的,到了j必然前边的数都有经过,所以我们在枚举是维护一个$cnt[i][a]-cnt[i][b]$的最小值即可(代码中用到minv数组)。

    代码中有p[i][j]数组表示更新字符i和字符j差的最小值的位置。

    总的时间复杂度$O(n imes 26)$

    #include<complex>
    #include<cstdio>
    using namespace std;
    const int N=1e6+7,M=27;
    int n,ans;
    int last[M],num[M],p[M][M],minv[M][M];
    /* last表示字符最后出现的位置,num表示字符出现的次数。
    p数组表示更新维护最小值的位置,minv表示维护的最小值。*/
    char s[N];
    int main()
    {
    //    freopen("B.in","r",stdin);
    //    freopen("B.out","w",stdout);
        scanf("%d%s",&n,s+1);
        for(int i=1; i<=n; i++)
        {
            int c=s[i]-'a';
            num[c]++;
            last[c]=i;
            for(int j=0; j<26; j++)
                if(j!=c && num[j])
                    ans=max(ans,max(num[c]-num[j]-minv[c][j]-(last[j]==p[c][j])
                                    ,num[j]-num[c]-minv[j][c]-(last[c]==p[j][c])));
            /*最后出现的位置与最小值更新的位置相等,那么在我们判断的区间里,
            不会出现j,对于这段区间-j,就等于只是选定区间内c出现的次数,
            这是不符合条件的,那么要让他更大,再向左选一个不同的字
            符那么tot[u]-1一定是最优的。*/
            for(int j=0; j<26; j++)
                if(num[j]-num[c]<minv[j][c])
                {
                    minv[j][c]=num[j]-num[c];
                    p[j][c]=i;
                }
            //更新最小值。
        }
        printf("%d
    ",ans);
    //    fclose(stdin);fclose(stdout);
        return 0;
    }
  • 相关阅读:
    永无乡「HNOI2012」
    ruby基础知识之 class&module
    Linux命令集锦
    Ruby知识总结-一般变量+操作符+if+数组和哈希
    VMware通过VMnet8共享本地网络
    VMware Workstation 不可恢复错误 (vcpu-0)
    WIN10安装时msxml4.0提示2502、2503解决办法
    C# 委托知识总结
    request.servervariables参数
    判断MS SQLSERVER临时表是否存在
  • 原文地址:https://www.cnblogs.com/rmy020718/p/9615482.html
Copyright © 2011-2022 走看看