E卷-分披萨-(100分)

分披萨

题目描述

K小姐和A先生到披萨店点了一份圆形披萨,并嘱咐店员将披萨切成大小相同的偶数块。但是粗心的服务员把披萨切成了大小不一的 块,且 为奇数。

为了公平起见,两人商量了一个取披萨的规则:从K小姐开始,轮流取披萨。除了第一块披萨可以随意选取外,其余的披萨必须从上一个人取完的披萨的相邻位置开始取。

A先生每次都会选择剩下披萨中最大的一块,而K小姐知道A先生的这个特点。现在给定每块披萨的大小,请问K小姐最多能够取到多少大小的披萨呢?

输入格式

第一行包含一个正整数 ,表示披萨被切成了 块。

接下来 行,每行一个正整数,第 行的整数表示第 块披萨的大小

输出格式

输出一个整数,表示K小姐最多能够取到的披萨大小之和。

样例输入

5
8
2
10
5
7

样例输出

19

数据范围

  • ,保证 为奇数

题解

动态规划

本题可以使用记忆化搜索来解决。

定义 表示当前还剩下第 块到第 块披萨时,K小姐能够取到的最大披萨大小之和。那么答案就是 ,其中

对于函数 ,我们可以分情况讨论:

  1. 如果 ,那么只剩下一块披萨,K小姐直接取走,因此

  2. 如果 ,那么A先生会取走两端披萨中较大的一块。设 分别表示取走披萨后的左右端点,那么有:

    • 如果 ,那么
    • 如果 ,那么

    因此

为了避免重复计算,我们可以使用记忆化数组 来保存已经计算过的状态。其中 表示当前还剩下第 块到第 块披萨时,K小姐能够取到的最大披萨大小之和。

时间复杂度 ,空间复杂度

参考代码

  • Python
# 读取输入
N = int(input())
A = [int(input()) for _ in range(N)]

# 初始化dp数组
dp = [[-1] * N for _ in range(N)]

def solve(L, R):
    # A先生取走较大的一块披萨
    if A[L] > A[R]:
        L = (L + 1) % N
    else:
        R = (R - 1 + N) % N
    
    # 如果已经计算过这种情况,直接返回结果
    if dp[L][R] != -1:
        return dp[L][R]
    
    # 如果只剩一块披萨,K小姐直接取走
    if L == R:
        dp[L][R] = A[L]
    else:
        # K小姐选择能使自己获得最大值的方案
        dp[L][R] = max(A[L] + solve((L+1)%N, R), A[R] + solve(L, (R-1+N)%N))
    
    return dp[L][R]

# 计算K小姐能获得的最大披萨大小
ans = 0
for i in range(N):
    ans = max(ans, solve((i+1)%N, (i-1+N)%N) + A[i])

# 输出结果
print(ans)
  • C
#include <stdio.h>
#include <string.h>

#define MAX_N 510
#define MAX(a, b) ((a) > (b) ? (a) : (b))

int N, A[MAX_N];
long long dp[MAX_N][MAX_N];

long long solve(int L, int R) {
    // A先生取走较大的一块披萨
    if (A[L] > A[R]) {
        L = (L + 1) % N;
    } else {
        R = (R - 1 + N) % N;
    }

    // 如果已经计算过这种情况,直接返回结果
    if (dp[L][R] != -1) {
        return dp[L][R];
    }

    // 如果只剩一块披萨,K小姐直接取走
    if (L == R) {
        dp[L][R] = A[L];
    } else {
        // K小姐选择能使自己获得最大值的方案
        dp[L][R] = MAX(A[L] + solve((L+1)%N, R), A[R] + solve(L, (R-1+N)%N));
    }

    return dp[L][R];
}

int main() {
    // 读取输入
    scanf("%d", &N);
    for (int i = 0; i < N; i++) {
        scanf("%d", &A[i]);
    }

    // 初始化dp数组
    memset(dp, -1, sizeof(dp));

    // 计算K小姐能获得的最大披萨大小
    long long ans = 0;
    for (int i = 0; i < N; i++) {
        ans = MAX(ans, solve((i+1)%N, (i-1+N)%N) + A[i]);
    }

    // 输出结果
    printf("%lld\n", ans);

    return 0;
}
  • Javascript
const readline = require('readline');
const rl = readline.createInte

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论
状态变化算法和你的一样,就是用递归了。没想出dp记忆存储的方案。
点赞 回复 分享
发布于 2025-02-17 18:04 上海
得了 70分,不知道哪里失分了
点赞 回复 分享
发布于 2025-02-17 18:03 上海

相关推荐

不愿透露姓名的神秘牛友
2025-12-17 16:48
今天九点半到公司,我跟往常一样先扫了眼电脑,屁活儿没有。寻思着没事干,就去蹲了个厕所,回来摸出手机刷了会儿。结果老板刚好路过,拍了我一下说上班别玩手机,我吓得赶紧揣兜里。也就过了四十分钟吧,我的直属领导把我叫到小隔间,上来就给我一句:“你玩手机这事儿把老板惹毛了,说白了,你可以重新找工作了,等下&nbsp;HR&nbsp;会来跟你谈。”&nbsp;我当时脑子直接宕机,一句话都没憋出来。后面&nbsp;HR&nbsp;找我谈话,直属领导也在旁边。HR&nbsp;说我这毛病不是一次两次了,属于屡教不改,不光上班玩手机,还用公司电脑看论文、弄学校的事儿。我当时人都傻了,上班摸鱼是不对,可我都是闲得发慌的时候才摸啊!而且玩手机这事儿,从来没人跟我说过后果这么严重,更没人告诉我在公司学个习也算犯错!连一次口头提醒都没有,哪儿来的屡教不改啊?更让我膈应的是,昨天部门刚开了会,说四个实习生里留一个转正,让大家好好表现。结果今天我就因为玩手机被开了。但搞笑的是,开会前直属领导就把我叫去小会议室,明明白白告诉我:“转正这事儿你就别想了,你的学历达不到我们部门要求,当初招你进来也没打算给你这个机会。”合着我没入贵厂的眼是吧?可我都已经被排除在转正名单外了,摸个鱼至于直接把我开了吗?真的太离谱了!
rush$0522:转正名单没进,大概率本来就没打算留你
摸鱼被leader发现了...
点赞 评论 收藏
分享
评论
3
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务