Educational Codeforces Round 63D. Beautiful Array(动态规划)

题意:

在一个数组里面,找一个连续子数组使得子数组和最大,这是最大子段和。

现在给定一个数x,要求,求数组中的某一个连续子数组乘上x之后,该数组的最大字段和是多少。

解法:

第一眼:毫无疑问这是线性DP,而且肯定就是最大字段和拓展一下。

第二眼:如果x是正的话,那就找出最大子段和然后乘上x,如果x是负的话,那就找出最小子段和,并且记录这一个最小子段和的位置,然后给对应位置乘上x后,在对原数组进行最大子段和。连wa。。。恍然醒悟,这种贪心的做法似乎不适用,如果x大于0的话显然是没问题的,不过如果x小于0,将最小子段和乘x并不能保证可以得到最优解。

例如:3  -1

-11  10 -11  ,明显只需要变一个11就行了。

第三眼:既然贪心不可行,尝试动态规划,声明dp[maxx][2],dp[i][0]:表示到i为止没有乘m的最大值,dp[i][1]:表示到i为止已经乘了m的最大值,那么转移就可以是:

dp[i][0] = max(dp[i-1][0]+a[i],a[i]);
dp[i][1] = max(max(dp[i-1][0]*m+a[i],dp[i-1][0]+a[i]*m),max(dp[i-1][1]+a[i],a[i]*m));

然而这种状态好像有问题,因为他只考虑了一个前面一部分元素乘m也就是dp[i-1][0]*m或者是当前元素乘m,但是并没有考虑从当前开始后x位乘m。也就是说,他一直考虑的是从开始到i位置的最大子段和乘m,并没有考虑到中间某一部分乘m的情况。

最后:如何维护中间某一段元素乘m的情况呢,那就给dp数组加一个表示中间相乘就ok。

定义:dp[max][3]:dp[i][0]:表示到i为止没有乘m的最大值,dp[i][1]:表示不知道从什么时候开始,但是一直乘m乘到第i个位置(处于正在被乘的区间),dp[i][2]:前面已经有段区间乘完m了,所以现在不能乘m了。这样子的状态就考虑到了中间某一部分。

转移:

        dp[i][0] = max(dp[i-1][0]+a[i],a[i]);
        dp[i][1] = max(dp[i-1][0]+a[i]*m,max(dp[i-1][1]+a[i]*m,a[i]*m));
        dp[i][2] = max(dp[i-1][1]+a[i],max(dp[i-1][2]+a[i],a[i]));

代码如下:

/*by kzl*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>

using namespace std;
const int maxx = 1e6+500;
const int INF = 0x3f3f3f3f;
typedef long long ll;

int n,m;
ll a[maxx];
char s[maxx];
ll mi = 1e18,ma = -1*1e18;
ll dp[maxx][3];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++){
        dp[i][0] = max(dp[i-1][0]+a[i],a[i]);
        dp[i][1] = max(dp[i-1][0]+a[i]*m,max(dp[i-1][1]+a[i]*m,a[i]*m));
        dp[i][2] = max(dp[i-1][1]+a[i],max(dp[i-1][2]+a[i],a[i]));
        ma = max(ma,max(dp[i][0],dp[i][1]));
        ma = max(ma,dp[i][2]);
    }
    printf("%lld\n",max(ma,0ll));
    return 0;
}

以上

### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线交集判断平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值