Three Blocks Palindrome (hard version&&easy)(Codeforces Round #634 (Div. 3))(dp、8错)

Three Blocks Palindrome

Codeforces Round #634 (Div. 3) 1335 E2
Codeforces Round #634 (Div. 3) 1335 E1
题意:
给定序列a,当子序列(不是子串!!!)是这个样子的时候就是合法的: [ a , a , ⋯   , a ⏟ x b , b , ⋯   , b ⏟ y a , a , ⋯   , a ] ⏟ x \begin{matrix} \underbrace{[ a,a,\cdots,a } \\ x \end{matrix}\begin{matrix} \underbrace{ b,b,\cdots,b } \\ y \end{matrix}\begin{matrix} \underbrace{ a,a,\cdots,a] } \\ x \end{matrix} [a,a,,ax b,b,,by a,a,,a]x.问合法串的最大长度。

简单版本:a长度大小2000,ai大小26
困难版本:a的长度大小2e5,ai的大小200.

简单版本

思路:
一开始没有看到是子序列以为是子串想简单了。
枚举中间b出现的的长度(一个头i,一个尾j)
mp1【i】【j】记录在1 ~ i位置出现的颜色j的个数。mp1【i】【j】记录在i ~ n 位置出现的颜色j的个数。
每次枚举中间长度时候再遍历26种颜色,记录最大值

int a[maxn],mp1[maxn][30],mp2[maxn][30];
int main(){
    int t=ird();
    int b,n,maxx,ans,co,t1,t2;
    while(t--){
        memset(mp1,0,sizeof mp1);
        memset(mp2,0,sizeof mp2);
        n=ird();
        ans=0;
        //a[0]=27;a[n+1]=27;
        for(int i=1;i<=n;i++){
            a[i]=ird();
            for(int j=1;j<=26;j++){
                mp1[i][j]=mp1[i-1][j];
            }
            mp1[i][a[i]]++;
        }
        for(int i=n;i>=1;i--){
            for(int j=1;j<=26;j++){
                mp2[i][j]=mp2[i+1][j];
            }
            mp2[i][a[i]]++;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++){
                for(int k=1;k<=26;k++){
                    if(a[i]==k) continue;
                    ans=max(ans,mp1[i][a[i]]-mp1[j-1][a[i]]+2*min(mp1[j][k],mp2[i][k]));
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

困难版本

思路:
简单版本的ijk三重循环必然tle。
思考为啥会tle:ij的枚举中其实多了很多重复不必要的试探

⟹ \Longrightarrow 不枚举中间段位置,改成枚举两边。因为要求两边的颜色一样,所以只要枚举两边的长度,然后遍历每种颜色,在这两个段所夹的中间段的长度中找到最大长度的b段。
mp[i][j]记录i颜色出现j次的第一个位置。dp[i][j]记录i位置j颜色出现的个数。

枚举两边的颜色i,遍历颜色i作为两边的最大长度,枚举中间段颜色k,用dp减出最大值(避免了重复不必要的试探)

int a[maxn],dp[maxn][250];
map<int,map<int,int> > mp;
int main(){
    int t=ird();
    int b,n,maxx,ans,co,t1,t2;
    while(t--){
        n=ird();
        ans=0;
        //a[0]=27;a[n+1]=27;
        for(int i=1;i<=n;i++){
            a[i]=ird();
            for(int j=1;j<=200;j++){
                dp[i][j]=0;
                dp[i][j]+=dp[i-1][j];
 
            }
            dp[i][a[i]]++;
            mp[a[i]][dp[i][a[i]]]=i;
        }
        for(int j=1;j<=200;j++){
            ans=max(ans,dp[n][j]);
            for(int i=1;i<=dp[n][j]/2;i++){
                t1=mp[j][i];t2=mp[j][dp[n][j]-i+1];
                for(int k=1;k<=200;k++){
                    if(j==k) continue;
                    ans=max(ans,2*i+dp[t2][k]-dp[t1][k]);
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值