专栏文章
题解:P14597 [COCI 2025/2026 #2] 递增 / Rastući
P14597题解参与者 3已保存评论 5
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @min1cfcv
- 此快照首次捕获于
- 2025/12/01 18:57 3 个月前
- 此快照最后确认于
- 2025/12/01 18:57 3 个月前
吐槽 C 题放紫卡我一年/pz
先转化一下题意:
给你一个长为 的序列,要划分为若干连续子段使得每段和单调不降,求划分的最大段数。
显然是一个比较经典的 dp。我们设 表示前 个数划分出的最大段数, 表示当前划分下最后一段的最小可能和。 的定义自不必说,那为什么这样定义 呢?其实也很简单,由于单调性只有当最后一段尽量小时后面能分得的段数才更多。
说完了状态再来考虑转移。对于每个 我们枚举最后一段的起点 ,记最后一段和为 ,要满足单调性只有 时才能转移。在所有合法 中优选最大的 ,若段数相同则选 更小的(原因前文讲过)。另外需要输出方案所以计一个 表示从哪转移,最后倒序输出即可。
CPP#include <bits/stdc++.h>
#define INF 1e18
using namespace std;
using ll=long long;
int n,a[5010];
ll sum[5010],f[5010],g[5010],pre[5010];
vector<ll> ans;
int main(){
cin>>n;
for(int i=1;i<=n;++i){
cin>>a[i];
sum[i]=sum[i-1]+a[i];
g[i]=INF,pre[i]=-1;
}
g[0]=0;
for(int i=1;i<=n;++i){
for(int j=0;j<i;++j){
ll s=sum[i]-sum[j];
if(s>=g[j]){
if(f[i]<f[j]+1 || (f[i]==f[j]+1 && s<g[i])){
f[i]=f[j]+1;
g[i]=s;
pre[i]=j;
}
}
}
}
int i=n;
while(i){
int j=pre[i];
ans.push_back(sum[i]-sum[j]);
i=j;
}
reverse(ans.begin(),ans.end());
cout<<ans.size()<<"\n";
for(int i=0;i<ans.size();++i) cout<<ans[i]<<" ";
return 0;
}
点个赞呗 qaq
相关推荐
评论
共 5 条评论,欢迎与作者交流。
正在加载评论...