BZOJ4384: [POI2015]Trzy wieże 记忆化搜索

http://www.lydsy.com/JudgeOnline/problem.php?id=4384
dp数组表示的是当前有两个数量相等,末尾字符是这两个中的一个且与它前面的字符不等,第三种的数量比这两个少1的情况。主要是基本相同的代码抄三遍所以看着比较长。。。时间复杂度o(n)。

#include<cstdio>
#include<algorithm>
#define gm 1000005
using namespace std;
int n,ans,pre[gm],suf[gm],dp[gm][3];
char s[gm];
int dfs(int pos,int a,int b,int c)
{
    if(pos<=1) return 1;
    if(a==b&&b==c&&a==c)
    {
        if(s[pos]=='S') goto S;
        if(s[pos]=='B') goto B;
        if(s[pos]=='C') goto C;
    }
    if(a==b)
    {
        if(s[pos]=='S'||s[pos]=='B')
        {
            if(a!=c+1) return pos-1;
            if(pre[pos]>1) return pos-2;
            if(dp[pos][0]) return dp[pos][0];
            return dp[pos][0]=dfs(pos-1,a-(s[pos]=='S'),b-(s[pos]=='B'),c);
        }
        C: return dfs(pos-pre[pos],a,b,c-pre[pos]);
    }
    if(b==c)
    {
        if(s[pos]=='B'||s[pos]=='C')
        {
            if(b!=a+1) return pos-1;
            if(pre[pos]>1) return pos-2;
            if(dp[pos][1]) return dp[pos][1];
            return dp[pos][1]=dfs(pos-1,a,b-(s[pos]=='B'),c-(s[pos]=='C'));
        }
        S: return dfs(pos-pre[pos],a-pre[pos],b,c);
    }
    if(a==c)
    {
        if(s[pos]=='S'||s[pos]=='C')
        {
            if(c!=b+1) return pos-1;
            if(pre[pos]>1) return pos-2;
            if(dp[pos][2]) return dp[pos][2];
            return dp[pos][2]=dfs(pos-1,a-(s[pos]=='S'),b,c-(s[pos]=='C'));
        }
        B: return dfs(pos-pre[pos],a,b-pre[pos],c);
    }
    return pos;
}
int main()
{
    scanf("%d",&n); fread(s,1,n+1,stdin); int a=0,b=0,c=0;
    for(int i=1;i<=n;++i) pre[i]=s[i-1]==s[i]?pre[i-1]+1:1,++(s[i]=='B'?b:s[i]=='C'?c:a);
    for(int i=n;i;--i) suf[i]=s[i+1]==s[i]?suf[i+1]+1:1;
    for(int i=1;i<=n;++i) 
    ans=max(ans,max(suf[i],dfs(n,a,b,c)-i+1)),--(s[i]=='B'?b:s[i]=='C'?c:a);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值