选与不选问题中的暂时答案假定思想

news/2025/3/31 17:09:38/文章来源:https://www.cnblogs.com/letscode/p/18798812

你有一个长度为 n 的数组 a ,由 n 个非零整数组成。最初,你有 0 枚硬币,你将进行以下操作,直到 a 为空:

  • 假设m是a的当前大小。选择一个整数 i , 其中1≤i≤m,获得|ai| 枚金币,这里的 |ai|表示 ai 的绝对值, 然后:
    • 如果是 ai<0,则用 [a1,a2,…,ai−1][a1,a2,…,ai−1] 替换 a (即删除以 ai 开头的后缀);
    • 否则,将 a 替换为 [ai+1,ai+2,…,am][ai+1,ai+2,…,am] (即删除以 ai 结尾的前缀)。

求过程结束时硬币的最大数量。

分析

有一些题不是用来模拟的,是用来假定答案的

这里引用一下cf的官方题解

首先我们可以看到,在任何时候,我们要么删除最左边的正数元素,要么删除最右边的负数元素,因为如果我们删除的不是最左边的正数元素,那么我们就可以先删除最左边的正数元素,从而获得更高的分数,而删除最右边的负数元素也有类似的道理。因此,要计算答案,我们只需检查将数组分成(正数)前缀和还有(负数)后缀(和)的所有 n+1 方法,并取其中的最大值,这在 O(n) 中很容易做到。

通过分析题意, 注意到 :

选正数-> 删前缀

选负数-> 删后缀

在选一个正数之前, 最优的解法是把它前面的正数都取了, (不拿白不拿)

在选一个负数之前, 最好把它后面的负数都拿了

我们扫一遍数组, 对于每一个数, 假设一个暂时的答案包含这个数, 那么最优的解法就是

把截止这个数之前的正数都取了, 把从这个数开始到末尾的负数都取了

(因为假设有取这个数,那么这个数前面的负数肯定不会取, 否则就会把这个数删了)

这个数后面的正数也不用取, 这本文思想的关键之一,乍一看这样怎么会使最终答案最优呢?

别忘了我们在遍历数组,如果还需要取后面的正数, 在遍历到后面的时候自会取到

我们并不是要一次模拟得出最终答案,对于一些"选与不选的问题"可以考虑"假设最终答案有选这个"的思想,在遍历(暴力枚举) 的过程中得到正确的答案

ac 代码

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define int long longconst int N=2e5+5;
int a[N];
int pre[N];
int tot[N];
void solve(){int n;cin>>n;rep(i,1,n)cin>>a[i];rep(i,1,n){if(a[i]>=0)pre[i]=pre[i-1]+a[i];else pre[i]=pre[i-1];}tot[n]=(a[n]>=0?0:-a[n]);for(int i=n-1;i>=1;i--){if(a[i]<0)tot[i]=tot[i+1]-a[i];else tot[i]=tot[i+1];}int ans=0;rep(i,1,n){ans=max(ans,pre[i]+tot[i]);}cout<<ans<<endl;/*以下没用, 是之前试图用模拟来做的解法*/// int ans=0;// int l=1,r=n;// while(l+1!=r){//     if(a[l]>=0){ans+=a[l++];continue;}//     if(a[r]<0){ans-=a[r--];continue;}//     while(a[l]<0&&l+1!=r)l++;//     while(a[r]>=0&&l+1!=r)r--;//     if// }// rep(i,1,n){//     if(a[i]>=0){//         ans+=a[i];//     }else{//         int p=i;//         while(p<=n&&a[p]<0)p++;//         p-=1;//         if(p==n){//             ans+=(tot[n]-tot[i-1]);//             break;//         }//         if((tot[p]-tot[i-1])<a[p+1]){//             ans+=a[p+1];//             i=p;//         }else{//         }//     }// }// cout<<ans<<endl;
}signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int _;cin>>_;while(_--)solve();return 0;
}

题目来自 Codeforces Round 1005 (Div. 2) C. Remove the Ends

后记: 杰哥说如果你想不到这种做法,说明你还得练

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/907315.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独立按键控制LED数码管

前言 通过1个独立按键,控制LED数码管显示字符。 结合之前我的两篇文章独立按键控制LED流水灯方向 https://www.cnblogs.com/luckydoog/p/18796974数码管静态显示 https://www.cnblogs.com/luckydoog/p/18797690效果原理 提前在程序里存储共阴极数码管的编码表,能表示的字符范…

day:32 jmeter操作数据库——参数化

一、数据库通过用户参数设置变量 1、建一个查询的jdbs请求2、前置处理器中添加用户参数3、修改线程数4、查看结果二、txt文档实现参数化 1.编辑sql语句中导入变量${变量名}新建一个txt文档:data 命名导入txt文档运行以上内容是将sql语句写入到txt文档中引用 2. 将数据写入txt文…

20242214 实验二《Python程序设计》实验报告

20242214 2024-2025-2 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2422 姓名: 陈冯 学号:20242214 实验教师:王志强 实验日期:2025年3月26日 必修/选修: 公选课 一、实验内容设计并完成一个完整的应用程序,完成加减乘除模等运算,功能多多益善:在VS…

SvelteKit 最新中文文档教程(13)—— Hooks

前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构…

day:32 jmeter操作数据库——安装及认识

一、jmeter数据库安装 1.下载数据驱动,安装数据驱动2、存放四个路径a.jre下的lib C:\ProgramFiles\Java\jre1.8.0_60\libb、存放在jre 下的lib 中的ext 路径: C:\ProgramFiles\Java\jre1.8.0_60\lib\extc、存放在jmeter下的lib 路径:D:\dcs\ruanjian\java\apache-jmeter-3.…

56. W5500以太网模块

一、W5500以太网模块W5500 是一款由 WIZnet 公司生产的以太网控制芯片,它集成了一个全双工的 10/100Mbps 以太网 MAC 和 PHY,以及一个硬件的 TCP/IP 协议栈。W5500 芯片通常被用于嵌入式系统中,为微控制器提供网络连接的能力,使得设备能够通过以太网进行数据传输和通信。W5…

[CF 1870E] Another MEX Problem

思路给你一个序列 \(a\), 让你选出一些不交的子段, 使得它们的 \(\rm{MEX}\) 的异或和最大不难发现因为是异或和, 可以简单转化成 \(\mathcal{O} (n^3)\) 的可行性 \(\rm{dp}\) 然后我进行了对固定右端点 \(r\) 一些优化尝试, 发现都比较寄 然后发现这个题, 它, 对, 右端点, 进…