Wannafly挑战赛28 - B.msc和mcc

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/sdau20163942/article/details/83931346

题目链接https://ac.nowcoder.com/acm/contest/217/B

本题解参考:https://blog.csdn.net/Jaihk662/article/details/83903786

题意:给出长为n的仅由'm','s','c'组成的字符串str[],问其中有多少区间[x,y]使得str[x,y]包含两个互不重叠的子序列'msc'和'mcc'。

解析:打表可以发现满足条件的区间[x,y]只需包含以下8种子序列:

mmsccc、mmcscc、mmccsc、msmccc、mscmcc、mcmscc、mcmcsc、mccmsc

        考虑只需枚举每个区间起点x,求一个最小的y,使得[x,y]是最短合法区间,那么起点x对答案的贡献就是n-y+1;如果对于x找不到合法y,那么它对答案贡献为0。考虑对于字符串str[]先求出net[][]数组:net[j][i]是str[j]后面字符i的最近位置('a'≤i≤'z')。那么枚举每个区间端点x时,先嵌套第二层循环枚举每一个合法序列,再嵌套第三层循环用next数组找最近的y,即可得到一个O(n*8*6)的算法。

代码(37ms)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
char str[MAXN];
char temp[20][20]={
    "mmsccc",
    "mmcscc",
    "mmccsc",
    "msmccc",
    "mscmcc",
    "mcmscc",
    "mcmcsc",
    "mccmsc"
};
int n,net[MAXN][28];

int main()
{
    scanf("%d",&n);
    scanf("%s",str+1);
    for(int i='a';i<='z';i++)
    {
        for(int j=n;j>=1;j--)
        {
            net[j-1][i-'a']=net[j][i-'a'];//net[j][i]是a[j]后面字符i的最近位置
            if(str[j]==(char)i)
                net[j-1][i-'a']=j;
        }
    }
    long long ans=0;
    for(int x=1;x<=n;x++)//枚举区间起点为i,寻找最小的y
    {
        int y=n+1;
        for(int i=0;i<8;i++)//每种合法字符串,其最早结束位置为now
        {
            int now=x-1;
            for(int j=0;j<6;j++)//合法的字符串长度为6
            {
                now=net[now][temp[i][j]-'a'];
                if(now==0) break;
            }
            if(now!=0) y=min(y,now);
        }
        ans+=n-y+1;
    }
    printf("%lld\n",ans);
    return 0;
}

打表代码:

#include<bits/stdc++.h>
using namespace std;
string str[800];//所有可能序列
string ans[800];//所有合法序列
int num,len;

void dfs(int step,string tmp)
{
    if(step>6) {str[++num]=tmp;return;}
    dfs(step+1,tmp+'m');
    dfs(step+1,tmp+'s');
    dfs(step+1,tmp+'c');
}

bool ok(int index)
{
    bool flag=false;
    for(int i=0;i<6;i++)
    {
        for(int j=i+1;j<6;j++)
        {
            for(int k=j+1;k<6;k++)
            {
                string tmp="";
                tmp+=str[index][i];
                tmp+=str[index][j];
                tmp+=str[index][k];
                if(tmp=="msc")
                {
                    tmp="";
                    for(int l=0;l<6;l++)
                    {
                        if(l!=i&&l!=j&&l!=k) tmp+=str[index][l];
                    }
                    if(tmp=="mcc") {flag=true;break;}
                }
            }
        }
    }
    return flag;
}

int main()
{
    dfs(1,"");

    for(int i=1;i<=num;i++)
    {
        if(ok(i)) ans[++len]=str[i];
    }
    for(int i=1;i<=len;i++)
        cout<<ans[i]<<endl;
    return 0;
}
/*
mmsccc
mmcscc
mmccsc
msmccc
mscmcc
mcmscc
mcmcsc
mccmsc
*/

猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/83931346
今日推荐