E. String Multiplication(想法)

原题: http://codeforces.com/contest/1131/problem/E

题意:

定义字符串 S ∗ T = T + S 1 ( 第 一 个 字 母 ) + T + . . . + S n + T S*T=T+S_1(第一个字母)+T+...+S_n+T ST=T+S1()+T+...+Sn+T,例如 a c ∗ b = b a b c b ac*b=babcb acb=babcb,现在给出n个串 P 1 . . . P n P_1...P_n P1...Pn,求目标串 ( . . ( P 1 ∗ P 2 ) ∗ P 3 ) . . . ) ∗ P n (..(P_1*P_2)*P_3)...)*P_n (..(P1P2)P3)...)Pn中,连续相同字符的个数的最大值( a b b b c = 3 abbbc=3 abbbc=3)。

解析:

可以分析出 ( . . ( P 1 ∗ P 2 ) ∗ P 3 ) . . . ) ∗ P n = P 1 ∗ ( . . . ( P n − 2 ∗ ( P n − 1 ∗ P n ) . . . ) (..(P_1*P_2)*P_3)...)*P_n=P_1*(...(P_{n-2}*(P_{n-1}*P_n)...) (..(P1P2)P3)...)Pn=P1(...(Pn2(Pn1Pn)...),即先从后面处理,这样有什么好处? S ∗ T S*T ST的意思其实是把 T T T插入到 S S S的各个位置,连接两块S的只有一个字符。这样最明显的优势为:只要 T T T已经非同一字符(至少两种字符),那么 S ∗ T S*T ST的左端连续相同字符和右端连续字符,不管在种类上还是长度上都和 T T T一样。

考虑可能变长的部分:

在这里插入图片描述
如果两边字符相同且等于x,那么长度为l+1+r。其他情况可自行考虑。

如果一直相同更好办, s u m ( 已 积 累 长 度 ) = l e n ( 当 前 段 长 度 ) + ( l e n + 1 ) ∗ s u m sum(已积累长度)=len(当前段长度)+(len+1)*sum sum()=len()+(len+1)sum

注意点:

  • 需要用最后一个串的最长连续相同子串更新答案。
  • 第一次出现不同时,假设累积串为 a a a aaa aaa,当前串为 b a a b baab baab,那么 a a a ∣ a ∣ a a a ∣ a ∣ a a a aaa|a|aaa|a|aaa aaaaaaaaaaa需要更新答案。

代码:

#include<bits/stdc++.h>
using namespace std;

string x[100009];

int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x[i];
    }
    int l=0,r=0;
    int ans=1;
    char L=x[n][0],R=x[n][x[n].length()-1];
    //***************考虑第一个串
    int co=1;
    for(int i=1;i<x[n].length();i++){
        if(x[n][i]==x[n][i-1])co++;
        else {
            ans=max(ans,co);
            co=1;
        }
    }
    ans=max(ans,co);


    int sum=0;
    if(x[n].length()==1){
        sum=1;
    }
    else{
        int i;
        for(i=1;i<x[n].length();i++){
            if(x[n][i]!=x[n][0])break;
        }
        i--;
        if(i==x[n].length()-1){
            sum=x[n].length();
        }
        else{
            l=i+1;
            for(i=x[n].length()-2;;i--){
                if(x[n][i]!=R)
                    break;
            }
            r=x[n].length()-1-i;
        }
    }
    ans=max(ans,max(sum,max(l,r)));
    //***************
    
    for(int i=n-1;i>=1;i--){
        if(!l){//还是全部相同
            int f=0;
            for(int j=0;j<x[i].length();j++){
                if(x[i][j]!=L){
                    f=1;
                    l=j+(j+1)*sum;
                    break;
                }
            }
            if(f){
                for(int j=x[i].length()-1;;j--){
                    if(x[i][j]!=R){
                        r=x[i].length()-1-j;
                        r=r+(r+1)*sum;
                        break;
                    }
                }
                //第一次出现不同时
                int co=0;
                for(int j=0;j<x[i].length();j++){
                    if(x[i][j]==L)co++;
                    else {
                        ans=max(ans,co+(co+1)*sum);
                        co=0;
                    }
                }
                ans=max(ans,co+(co+1)*sum);
            }
            else{
                sum=x[i].length()+(x[i].length()+1)*sum;
            }
        }
        else{
            for(int j=0;j<x[i].length();j++){
                if(x[i][j]==L){
                    if(L==R){
                        ans=max(ans,l+r+1);
                    }
                    else{
                        ans=max(ans,l+1);
                    }
                }
                else if(x[i][j]==R){
                    ans=max(ans,r+1);
                }
            }
        }
    }
    ans=max(ans,max(sum,max(l,r)));
    printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值