562. 壁画(acwing)

562. 壁画

Thanh 想在一面被均分为 N 段的墙上画一幅精美的壁画。

每段墙面都有一个美观评分,这表示它的美观程度(如果它的上面有画的话)。

不幸的是,由于洪水泛滥,墙体开始崩溃,所以他需要加快他的作画进度!

每天 Thanh 可以绘制一段墙体。

在第一天,他可以自由的选择任意一段墙面进行绘制。

在接下来的每一天,他只能选择与绘制完成的墙面相邻的墙段进行作画,因为他不想分开壁画。

在每天结束时,一段未被涂颜料的墙将被摧毁(Thanh 使用的是防水涂料,因此涂漆的部分不能被破坏),且被毁掉的墙段一定只与一段还未被毁掉的墙面相邻。

Thanh 的壁画的总体美观程度将等于他作画的所有墙段的美观评分的总和。

Thanh想要保证,无论墙壁是如何被摧毁的,他都可以达到至少 B 的美观总分。

请问他能够保证达到的美观总分 B 的最大值是多少。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据的第一行包含整数 N。

第二行包含一个长度为 N 的字符串,字符串由数字 0∼9 构成,第 i 个字符表示第 i 段墙面被上色后能达到的美观评分。

输出格式
每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 x 为组别编号(从 1 开始),y 为 Thanh 可以保证达到的美观评分的最大值。

数据范围
1≤T≤100,
存在一个测试点N=5∗106,其他测试点均满足2≤N≤100
输入样例:

4
4
1332
4
9583
3
616
10
1029384756

输出样例:

Case #1: 6
Case #2: 14
Case #3: 7
Case #4: 31

样例解释
在第一个样例中,无论墙壁如何被破坏,Thanh都可以获得 6 分的美观总分。在第一天,他可以随便选一个美观评分3的墙段进行绘画。在一天结束时,第一部分或第四部分将被摧毁,但无论哪一部分都无关紧要。在第二天,他都可以在另一段美观评分 3 的墙段上作画。

在第二个样例中,Thanh 在第一天选择最左边的美观评分为 9 的墙段上作画。在第一天结束时唯一可以被毁掉的墙体是最右边的那段墙体,因为最左边的墙壁被涂上了颜料。在第二天,他可以选择在左数第二段评分为 5 的墙面上作画。然后右数第二段墙体被摧毁。请注意,在第二天,Thanh不能选择绘制第三段墙面,因为它不与任何其他作画墙面相邻。这样可以获得 14 分的美观总分。

前缀和+滑动窗口

#include<bits/stdc++.h>
using namespace std;

const int z=1e7;

int s[z];
char a[z];

int main()
{
    int t,n,i,j;
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        scanf("%d",&n);
        scanf("%s",a+1);
        for(j=1;j<=n;j++)
            s[j]=s[j-1]+a[j]-'0';
        
        int res=0,m=(n+1)/2;
        for(j=m;j<=n;j++)
            res=max(res,s[j]-s[j-m]);
        printf("Case #%d: %d\n",i,res);
    }
    return 0;
}

解释:

  1. 程序定义了一个非常大的常数 z=1e7,这是为了确保数组 as 足够大,能够存储最大可能的输入数据。

  2. int s[z]; 定义了一个整型数组 s,它用来存储前缀和,即直到当前位置的墙段美观评分之和。

  3. char a[z]; 定义了一个字符型数组 a,用来存储输入的每段墙的美观评分。

  4. 程序首先读入测试用例的数量 t

  5. for(i=1;i<=t;i++) 这个循环遍历每一个测试用例。

  6. 对于每个测试案例,读入墙段总数 n 和每段墙的美观评分(存储在数组 a 里,下标从1开始)。

  7. 接着,通过一个循环 for(j=1;j<=n;j++) 计算前缀和数组 s,其中 s[j]=s[j-1]+a[j]-'0'; 这段代码将字符类型的评分转化为整数,并加到前缀和上。

  8. int res=0,m=(n+1)/2; 这里定义了两个变量,res 用来存储最大的美观总分,m 计算中间点,即Thanh 可以确保绘画的最小连续墙段数量。由于墙壁每天都会崩溃一段,所以他至少能绘制 (n+1)/2 个墙段。

  9. 接下来,在 for(j=m;j<=n;j++) 循环中,通过 res=max(res,s[j]-s[j-m]); 更新 res。这里,s[j]-s[j-m] 计算的是从第 j-m+1 段到第 j 段的连续墙段的美观评分和。我们要找的是这个和的最大值。

  10. 最后,使用 printf("Case #%d: %d\n",i,res); 输出每组数据的结果。

这段代码的核心思想是使用滑动窗口的方法来维护一个长度为 m 的连续墙段的美观评分总和,并在所有可能的位置中找到可以保证的最大美观评分。
在这里插入图片描述

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值