题解:P3590 [POI 2015] TRZ

P3590 题解

题面

原题传送门

思路

由于这个帖子没有人给出 hack,所以我就照着这个思路开始证明。

结论:最终答案的左端点在 13 的位置之一或者右端点在 n2n 的位置之一。

假设目前的字符串 a1 a2 a3 res a4 a5 a6,其中 res 为当前的最优解。

  1. res 中只有一个字符 ch,则有两种情况。
    1. |ch|=1,则 res 可以在 a16 里任意一个,所以满足结论。
    2. |ch|>1,则单独考虑 res a4,若 a4=ch,则 res 可以扩展;若 a4ch,则 |a4|=1,此时 |a4||ch|,所以在这种情况下,结论成立。
  2. res 中有多个字符,那么这三个字符的出现次数不一样,不妨设 |B|>|C|>|S|,则又有三种情况。
    1. a3= Ba4= B,则 res 可以继续往外扩展。
    2. a3= Ca4= C,设 a4= C,若 res 可以扩展到 a4,则满足结论;若不能扩展到 a4,则有 |B|=|C|+1,接下来考虑扩展 a3,a5,若 a3,a5 中有一个为 BC,则可以扩展;若 a3,a5= S,于是考虑 a3 resS res,若 res 可以扩展到 a3,则满足结论;若不能扩展,则有 |C|=|S|+1,于是联立下前面的式子,res 里字母数量满足 |B|=|C|+1=|S|+2。继续讨论,若 a2= B,则 a2 a3 res a4B S res C 满足题意;若 a2= C,则 a2 a3 res a4C S res C 满足题意;若 a2= S,继续讨论 a1,若 a1= B,则 a1 a2 a3 resB S S res 满足题意;若 a1= S,则 a1 a2 a3 resS S S res 满足题意;若 a1= C,继续讨论 a6,若 a6= B,则 res a4 a5 a6res C S B 满足题意;若 a6= C,则 res a4 a5 a6res C S C 满足题意;若 a6= S,则 a1 a2 a3 res a4 a5 a6C S S res C S S 满足题意。综上所述,当 a4= C 时,res 可以扩展。
    3. a3,a4= S(一个为 S 的情况上面已经讨论),若 a3 resa3 res a4 都不能扩展,则有 |B|=|C|+1=|S|+2,接下来考虑 a2,a5,若 a2,a5= B,则 a2 a3 res a4C S res S 满足题意,a5 同理也满足题意;若 a2,a5= S,则 a2 a3 res a4S S res S 满足题意,a5 同理也满足题意;若 a2,a5= C,继续考虑 a1,a6,若 a1,a6= B,则 a1 a2 a3 resB C S res 满足题意,a6 同理也满足题意;若 a1,a6= C,则 a1 a2 a3 resC C S res 满足题意,a6 同理也满足题意;若 a1,a6= S,则 a1 a2 a3 res a4 a5 a6S C S res S C 满足题意,a6 同理也满足题意。综上所述,a3,a4= S 时,res 可以扩展。

证毕,所以只要用前缀和记录下字符串字母出现的次数,一个个判断过去即可,时间复杂度为 O(n)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int MN=1e6+5;
ll n,s[MN][3],ans=1;
char c[MN];
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
char gc(){char ch=getchar();while(ch!='B'&&ch!='C'&&ch!='S')ch=getchar();return ch;}
ll gs(char ch){if(ch=='C') return 0;if(ch=='B') return 1;return 2;}
int main(){
    n=read();
    for(int i=1; i<=n; i++){
        c[i]=gc();
        s[i][gs(c[i])]++;
    }
    for(int i=1; i<=n; i++) for(int j=0; j<3; j++) s[i][j]+=s[i-1][j];
    for(int i=1; i<=3; i++) for(int j=n; j>i; j--) if((s[j][0]-s[i-1][0]!=s[j][1]-s[i-1][1]&&s[j][1]-s[i-1][1]!=s[j][2]-s[i-1][2]&&s[j][0]-s[i-1][0]!=s[j][2]-s[i-1][2])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][0]-s[i-1][0])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][1]-s[i-1][1])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][2]-s[i-1][2])) ans=max(ans,(ll)j-i+1);
    for(int j=n; j>n-3; j--) for(int i=1; i<j; i++) if((s[j][0]-s[i-1][0]!=s[j][1]-s[i-1][1]&&s[j][1]-s[i-1][1]!=s[j][2]-s[i-1][2]&&s[j][0]-s[i-1][0]!=s[j][2]-s[i-1][2])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][0]-s[i-1][0])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][1]-s[i-1][1])||(s[j][0]-s[i-1][0]+s[j][1]-s[i-1][1]+s[j][2]-s[i-1][2]==s[j][2]-s[i-1][2])) ans=max(ans,(ll)j-i+1);
    write(ans);putchar('\n');
    return 0;
}
posted @   naroto2022  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
战斗是残酷的,无法做出多余的考虑!