• [LuoguP1203][USACO1.1]P1203 Broken Necklace


    Solution

    这道题数据规模奇小,因此大部分人都使用了暴力搜索的方法,这也是我一开始的想法。

    对于 100100% 的数据,3n3503≤n≤350

    的确可以如此,但暴力搜索的方法也需要进行一些奇怪的判断,因此我又决定直接打dp的解法,其实dp也是很自然的一种想法……

    Dynamic Programming

    我们可以发现,每个点向左向右,取蓝色取红色能连续取的个数一定是确定的。
    于是我们定义dp数组:

    int lr[maxn];
    //lr[i]代表从i点向左不取i点
    //即在 [1,i-1] 范围内从i-1开始能连续取多少个红色珠子
    int lb[maxn];
    //lb[i]代表从i点向左不取i点
    //即在 [1,i-1] 范围内从i-1开始能连续取多少个蓝色珠子
    int rr[maxn];
    //rr[i]代表从i点向右取i点
    //即在[i,n] 范围内从i开始能连续取多少个红色珠子
    int rb[maxn];
    //rb[i]代表从i点向右取i点
    //即在[i,n] 范围内从i开始能连续取多少个蓝色珠子
    

    那么在一个点断开,能取得的珠子个数就是:
    ans[i]=max(lr[i],lb[i])+max(rr[i],rb[i])ans[i] = max(lr[i],lb[i]) + max(rr[i],rb[i])

    相信转移方程非常自然吧,我们先考虑向左取的情况:

    1. 前一个点为白色,那么有:
      lr[i]=lr[i1]+1lr[i] = lr[i-1] + 1
      lb[i]=lb[i1]+1lb[i] = lb[i-1] + 1
    2. 前一个点为红色,那么有:
      lr[i]=lr[i1]+1lr[i] = lr[i-1] + 1
      lb[i]=0lb[i] = 0
    3. 前一个点为蓝色,那么有:
      lr[i]=0lr[i] = 0
      lb[i]=lb[i1]+1lb[i] = lb[i-1] + 1

    为什么考虑前一个点呢?
    因为lr[i]lr[i]lb[i]lb[i]代表的是区间[1,i1][1,i-1]内从点i1i-1开始取能连续取多少,因此实际考虑的是点i1i-1的颜色。
    向右的情况也是同理,有:

    1. 当前点为白色,那么有:
      rr[i]=rr[i+1]+1rr[i] = rr[i+1] + 1
      rb[i]=rb[i+1]+1rb[i] = rb[i+1] + 1
    2. 当前点为红色,那么有:
      rr[i]=rr[i+1]+1rr[i] = rr[i+1] + 1
      rb[i]=0rb[i] = 0
    3. 当前点为蓝色,那么有:
      rr[i]=0rr[i] = 0
      rb[i]=rb[i+1]+1rb[i] = rb[i+1] + 1
      实现也很简单:
    for (int i = 2; i <= n; ++i)
    {
       if (s[i - 1] == 'w')
            lb[i] = lb[i - 1] + 1, lr[i] = lr[i - 1] + 1;
        else if (s[i - 1] == 'b')
            lb[i] = lb[i - 1] + 1, lr[i] = 0;
        else
            lb[i] = 0, lr[i] = lr[i - 1] + 1;
    }
    for (int i = n - 1; i; --i)
    {
        if (s[i] == 'w')
            rb[i] = rb[i + 1] + 1, rr[i] = rr[i + 1] + 1;
        else if (s[i] == 'b')
            rb[i] = rb[i + 1] + 1, rr[i] = 0;
        else
            rb[i] = 0, rr[i] = rr[i + 1] + 1;
    }
    

    Finally

    于是我们处理出了每个点向左向右取红取蓝最多能连续取多少个珠子。
    那么从i1i-1点,向左最多能取多少呢?
    left[i1]=max(lr[i],lb[i])left[i-1] = max(lr[i],lb[i])
    ii点,向右最多能取
    right[i]=max(rr[i],rb[i])right[i] = max(rr[i],rb[i])
    假定我们断开i1i-1ii,那么答案就是:
    ans=left[i1]+right[i]ans = left[i-1] + right[i]

    ans=max(lr[i],lb[i])+max(rr[i],rb[i])ans = max(lr[i],lb[i]) + max(rr[i],rb[i])
    最后扫一遍统计答案即可。

    int ans = 0;
    for (int i = 1; i <= n; ++i)
        ans = max(ans, max(lb[i], lr[i]) + max(rb[i], rr[i]));
    

    当然,还要注意答案不能超过原始的长度。

    Code

    拆环为链等细节就不赘述了。

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn = 710;
    char s[maxn];
    int n,lb[maxn], lr[maxn], rb[maxn], rr[maxn];
    inline int max(const int &a, const int &b) { return a > b ? a : b; }
    int main()
    {
        scanf("%d%s", &n, s + 1);
        memcpy(s + n + 1, s + 1, n);
        n <<= 1;
        for (int i = 2; i <= n; ++i)
        {
            if (s[i - 1] == 'w')
                lb[i] = lb[i - 1] + 1, lr[i] = lr[i - 1] + 1;
            else if (s[i - 1] == 'b')
                lb[i] = lb[i - 1] + 1, lr[i] = 0;
            else
                lb[i] = 0, lr[i] = lr[i - 1] + 1;
        }
        for (int i = n - 1; i; --i)
        {
            if (s[i] == 'w')
                rb[i] = rb[i + 1] + 1, rr[i] = rr[i + 1] + 1;
            else if (s[i] == 'b')
                rb[i] = rb[i + 1] + 1, rr[i] = 0;
            else
                rb[i] = 0, rr[i] = rr[i + 1] + 1;
        }
        int ans = 0;
        for (int i = 1; i <= n; ++i)
            ans = max(ans, max(lb[i], lr[i]) + max(rb[i], rr[i]));
        if (ans > n >> 1)
            ans = n >> 1;
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    联通手机号停机保号了,想恢复要短信验证码登陆但是无法接收短信验证码怎么办
    记卖饭让我先吃
    POJ 3658 Artificial Lake
    POJ 3662 Telephone Lines (dijstra+二分)
    CodeForces 748C Santa Claus and Robot
    CodeForces 748B Santa Claus and Keyboard Check
    POJ 3659 Cell Phone Network(树形dp树的最小点支配集)
    【JZOJ 5455】拆网线 【树形DP】
    【JZOJ 5455】拆网线 【树形DP】
    【JZOJ 5455】拆网线 【树形DP】
  • 原文地址:https://www.cnblogs.com/Clouder-Blog/p/12146634.html
Copyright © 2020-2023  润新知