选与不选问题中的暂时答案假定思想
你有一个长度为 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 long
const 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
后记: 杰哥说如果你想不到这种做法,说明你还得练

浙公网安备 33010602011771号