Solution

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

对于 100100%100 的数据,3≤n≤3503≤n≤3503≤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])ans[i]=max(lr[i],lb[i])+max(rr[i],rb[i])

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

  1. 前一个点为白色,那么有:

    lr[i]=lr[i−1]+1lr[i] = lr[i-1] + 1lr[i]=lr[i−1]+1

    lb[i]=lb[i−1]+1lb[i] = lb[i-1] + 1lb[i]=lb[i−1]+1
  2. 前一个点为红色,那么有:

    lr[i]=lr[i−1]+1lr[i] = lr[i-1] + 1lr[i]=lr[i−1]+1

    lb[i]=0lb[i] = 0lb[i]=0
  3. 前一个点为蓝色,那么有:

    lr[i]=0lr[i] = 0lr[i]=0

    lb[i]=lb[i−1]+1lb[i] = lb[i-1] + 1lb[i]=lb[i−1]+1

为什么考虑前一个点呢?

因为lr[i]lr[i]lr[i]和lb[i]lb[i]lb[i]代表的是区间[1,i−1][1,i-1][1,i−1]内从点i−1i-1i−1开始取能连续取多少,因此实际考虑的是点i−1i-1i−1的颜色。

向右的情况也是同理,有:

  1. 当前点为白色,那么有:

    rr[i]=rr[i+1]+1rr[i] = rr[i+1] + 1rr[i]=rr[i+1]+1

    rb[i]=rb[i+1]+1rb[i] = rb[i+1] + 1rb[i]=rb[i+1]+1
  2. 当前点为红色,那么有:

    rr[i]=rr[i+1]+1rr[i] = rr[i+1] + 1rr[i]=rr[i+1]+1

    rb[i]=0rb[i] = 0rb[i]=0
  3. 当前点为蓝色,那么有:

    rr[i]=0rr[i] = 0rr[i]=0

    rb[i]=rb[i+1]+1rb[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

于是我们处理出了每个点向左向右取红取蓝最多能连续取多少个珠子。

那么从i−1i-1i−1点,向左最多能取多少呢?

left[i−1]=max(lr[i],lb[i])left[i-1] = max(lr[i],lb[i])left[i−1]=max(lr[i],lb[i])

从iii点,向右最多能取

right[i]=max(rr[i],rb[i])right[i] = max(rr[i],rb[i])right[i]=max(rr[i],rb[i])

假定我们断开i−1i-1i−1和iii,那么答案就是:

ans=left[i−1]+right[i]ans = left[i-1] + 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])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\n", ans);
return 0;
}

[LuoguP1203][USACO1.1]P1203 Broken Necklace的更多相关文章

  1. 【USACO1.1】Broken Necklace

    题意 一个环形项链,有rbw三种珠子,r代表red,b代表blue,w代表white,从任意一个位置断开,两端分别取珠子,同一端取的珠子要相同颜色,w可以染成想要的颜色,即既可当作r也可以当作b,求最 ...

  2. P1203 [USACO1.1]坏掉的项链Broken Necklace

    P1203 [USACO1.1]坏掉的项链Broken Necklace不错的断环为链的模拟题,开成三倍,有很多细节要考虑,比如总长度要<=n,开头第一个是w等等. #include<bi ...

  3. 【P1203】 【USACO1.1】坏掉的项链Broken Necklace

    P1203 [USACO1.1]坏掉的项链Broken Necklace 题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 ...

  4. P1203 [USACO1.1]Broken Necklace(模拟-枚举)

    P1203 [USACO1.1]坏掉的项链Broken Necklace 题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 ...

  5. 题解 P1203 【[USACO1.1]坏掉的项链Broken Necklace】

    [USACO1.1]坏掉的项链Broken Necklace 22892 破碎的项链 方法一:很容易想到枚举断点,再分别两头找,但是要注意很多细节 #include<iostream> # ...

  6. 洛谷 P1203 [USACO1.1]坏掉的项链Broken Necklace

    坏掉的项链Broken Necklace 难度:★ Code: #include <iostream> #include <cstdio> #include <cstri ...

  7. [USACO1.1.4]坏掉的项链Broken Necklace

    P1203 [USACO1.1]坏掉的项链Broken Necklace 标签 搜索/枚举 USACO 难度 普及- 题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N&l ...

  8. 洛谷P1203 [USACO1.1]坏掉的项链Broken Necklace

    题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 n=29 的二个例子: 第一和第二个珠子在图片中已经被作记号. 图片 A ...

  9. AC日记——[USACO1.1]坏掉的项链Broken Necklace 洛谷 P1203

    题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 n=29 的二个例子: 第一和第二个珠子在图片中已经被作记号. 图片 A ...

随机推荐

  1. 利用 systemd 实现 Clash 开机自启

    利用 systemd 实现 Clash 开机自启 首先准备 Clash 的服务脚本,并保存为/etc/systemd/system/clash.service.内容如下: [Unit] Descrip ...

  2. PowerDesigner每点击一次就会提示打印错误对话框

    把服务启用了就好了: 重启软件

  3. python 编程的 Style Guide

    Python 的作者既优雅又高冷又 鬼毛的 再 PEP8 里规定了 Python 程序编写规范.(风格和格式) 一.基本观念 1.可读性之上,代码被读的次数肯定比被写的次数多.因此作者十分重视代码的可 ...

  4. PyQt5绘图API

    PyQt5绘图API大全1.绘图API:绘制文本#1.文本 2.各种图形 3.图像#QPainter painter=QPainter() painter.begin() painter.end() ...

  5. Java学习资源 - J2SE

    java.lang包教程 Java集合类详解 Java回顾之集合 Java回顾之序列化 Java回顾之反射 深入理解Java:类加载机制及反射 Java 下高效的反射工具包 ReflectASM 使用 ...

  6. 学习笔记——springMVC架构

    springMVC是一个MVC模式的实现,至于具体什么是MVC大佬们写了多很详细的博文给出一些链接: 链接1. SpringMVC框架“简单”执行流程 1.首先用户(或浏览器)发送请求到服务端. 2. ...

  7. java finalize学习

    1 finalize()调用的时机 与C++的析构函数(对象在清除之前析构函数会被调用)不同,在Java中,由于GC的自动回收机制,因而并不能保证finalize方法会被及时地执行(垃圾对象的回收时机 ...

  8. php 微信小程序支付

    php 微信小程序支付 直接贴代码: 前端测试按钮wxml: <view class="container"> <text class="name&qu ...

  9. ipmitool命令

    1.remote access control powerIpmitool -I lanplus -H 192.168.0.10 -U username -P Password chassis pow ...

  10. PPT页面切换动画

    想要自己的PPT更加炫酷一些的话,可以再给每个页面的切换,加上动画效果. 第一步,按住ctrl键,鼠标点击选择想要增加切换动画的页面,然后点击菜单栏的“切换” 第二步,在切换菜单下面选择具体的切换效果 ...