作诗2(玄学)

SHY是T国的公主,平时的一大爱好是作诗。不过这次赶潮流的SHY作了一首英文诗。
英文诗的长度为N,用一个仅含有26个小写拉丁字母的字符串表示。
SHY把这首诗拿给LYD欣赏,LYD突发奇想,想从这首诗中找出一段,使得这一段中出现最多的字母出现的次数与出现最少的字母出现的次数的差值最大。
现在请你求出这个最大差值吧。

Solution

这题看起来一脸不可做。(其实的确也不可做

它的数据范围只支持我们至多使用n*26或n*logn的做法。

正解就是在扫描序列是动态维护一个数组。

设dp[i][j]表示在我们扫描序列的过程中,以i为出现次数最多的项,以j为出现次数最少的项,最大差值。

now[i][j]表示与此同时,j有没有出现过(统计i有没有出现过没有意义)。

pre[i][j]表示与此同时,我、序列有没有前导j(baaaaab)这种情况我们就把b删掉。

具体看代码注释。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,dp[30][30],ans;
char s[1000002];
bool now[30][30],pre[30][30];
inline void getst(){
    int top=0;
    char c=getchar();while(!isalpha(c))c=getchar();
    while(isalpha(c))s[++top]=c,c=getchar();
}
int main(){
    while(scanf("%d",&n)!=EOF){
        memset(dp,0,sizeof(dp));ans=0;
        getst();
        for(int i=1;i<=n;++i){
            int x=s[i]-'a';
            for(int j=0;j<26;++j){
                dp[x][j]++;//在这里我们不关心是否有j出现过,直接加上 
                if(dp[x][j]>ans&&now[x][j])ans=dp[x][j];
                //只有当j出现过时我们才统计到答案里 
                dp[j][x]--;now[j][x]=1;//对于j为出现次数最多的情况,我们标记x出现过。 
                if(pre[j][x])dp[j][x]++,pre[j][x]=0;
                //这里比较关键我们可以舍去最前面的字符(因为我们已经保证存在性了 
                if(dp[j][x]>ans)ans=dp[j][x];
                if(dp[j][x]<-1)dp[j][x]=-1;//小于-1就没有意义了,小数只在前面出现一次就好了。 
                if(dp[j][x]==-1)pre[j][x]=1;//为-1时说明只有一个x,我们先保证存在性留到后面再出现一个j时把它减掉、 
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-09-19 17:18  comld  阅读(182)  评论(0编辑  收藏  举报