bzoj4384: [POI2015]Trzy wieże

题目
去年暑假在另一个网站DBOJ上也做到了,一点都不会,只能靠暴力骗分水过去

Description

给定一个长度为 n n n 的仅包含 B \texttt B B C \texttt C C S \texttt S S 三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同。

Solution

以下把B,C,S看作A,B,C

结论一:对于满足条件的最长子段 [ l , r ] [l,r] [l,r],只有两种情况:①3种字母个数都相差1;② l = 1 l=1 l=1 r = n r=n r=n

证明:假设最优解的 a < b < c a<b<c a<b<c。首先, c − b c-b cb b − a b-a ba不可能都大于1,。
若①②不成立,则 b − a > 1 b-a>1 ba>1 c − b > 1 c-b>1 cb>1
不妨设 b − a > 1 b-a>1 ba>1,则 c − b = 1 c-b=1 cb=1
因为②不成立,所以右边的位置不能是 a a a, c c c,只能是 b b b,左边也是这样(不然还能更优)。
此时 a < c < b + 2 a<c<b+2 a<c<b+2,能得到更优解,所以原来的不是最优解

结论二:对于子段 [ l , r ] [l,r] [l,r],当 l ∈ [ 1 , 3 ] l∈[1,3] l[1,3] r ∈ [ n − 2 , n ] r∈[n−2,n] r[n2,n]时一定能找到最优解。

证明:假设最优解 3 < l < = r < n − 2 3<l<=r<n-2 3<l<=r<n2
不妨令此时的 A , B , C A,B,C A,B,C个数分别为 x , x + 1 , x + 2 x,x+1,x+2 x,x+1,x+2
左右都扩展三位,假如能证明扩展后一定存在更优方案,我们可以通过不断扩展来保证 l ∈ [ 1 , 3 ] l∈[1,3] l[1,3] r ∈ [ n − 2 , n ] r∈[n−2,n] r[n2,n]成立
反证法,假设不存在更优方案, l − 1 , r + 1 l-1,r+1 l1,r+1处显然不能有 C C C,也不能同时为 B B B,那么分类讨论
1 A 1 B 1A1B 1A1B,情况变成 A X B AXB AXB A , B , C A,B,C A,B,C总个数分别为 x + 1 , x + 2 , x + 2 x+1,x+2,x+2 x+1,x+2,x+2,其中 X X X代表扩展前最优解
2 A 2A 2A,情况变成 A X A AXA AXA A , B , C A,B,C A,B,C总个数分别为 x + 2 , x + 1 , x + 2 x+2,x+1,x+2 x+2,x+1,x+2
对于①,显然两端不能有 B B B也不能有 C C C(不然有一个就能变 x + 3 x+3 x+3了),情况变成 A A X B A AAXBA AAXBA
由于 X B A XBA XBA对应 x + 1 , x + 2 , x + 2 x+1,x+2,x+2 x+1,x+2,x+2,所以右侧只能放 A A A A A X AAX AAX对应 x + 2 , x + 1 , x + 2 x+2,x+1,x+2 x+2,x+1,x+2,所以左侧只能放 B B B,情况变成 B A A X B A A BAAXBAA BAAXBAA,此时总个数 x + 4 , x + 3 , x + 2 x+4,x+3,x+2 x+4,x+3,x+2,还是出现了更优方案,矛盾
对于②,显然两端不能有 A A A C C C,情况变成 B A X A B BAXAB BAXAB
由于 X A B XAB XAB对应 x + 1 , x + 2 , x + 2 x+1,x+2,x+2 x+1,x+2,x+2,所以右侧只能放 A A A,左侧 B A X BAX BAX,情况一样,也只能放 A A A,状态变成 A B A X A B A ABAXABA ABAXABA,总个数 x + 4 , x + 3 , x + 2 x+4,x+3,x+2 x+4,x+3,x+2,更优,矛盾
综上,结论成立

Code

#include<bits/stdc++.h>
using namespace std;
const int N=1000002;
char s1[N];
int i,ans,A,B,C,a[N],b[N],c[N],n,j;
int main(){
    scanf("%d%s",&n,s1+1);
    for (i=1;i<=n;i++) a[i]=a[i-1]+(s1[i]=='B'),b[i]=b[i-1]+(s1[i]=='C'),c[i]=c[i-1]+(s1[i]=='S');
    for (i=1;i<=3;i++)
        for (j=n;j-i+1>ans;j--){
            A=a[j]-a[i-1];B=b[j]-b[i-1];C=c[j]-c[i-1];
            if (A!=B && A!=C && B!=C || (!A)+(!B)+(!C)==2){
                ans=j-i+1;
                break;
            }
        }
    for (j=n-2;j<=n;j++)
        for (i=1;j-i+1>ans;i++){
            A=a[j]-a[i-1];B=b[j]-b[i-1];C=c[j]-c[i-1];
            if (A!=B && A!=C && B!=C || (!A)+(!B)+(!C)==2){
                ans=j-i+1;
                break;
            }
        }
    printf("%d",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值