cf1526 C Potions
题意:
n个药剂,每个药剂可以加/减能量,一开始能量为0,从左往右开始进行,全程能量不为负,问最多可以使用几个药剂
本题有简单(n<2000),困难模式(n≤200000)
题解:
简单题解:
第一反应肯定是dp
设dp[i][j]为前i个药吃了j个,获得的最大能量
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+a[i])
求完dp后
倒着循环找第一个大于0等dp[n][i]就是答案
代码为状态压缩成一维的
困难题解:
当n<=200000时,dp就会超时
我们现在认为存在后悔情况,对于当前第i个药,如果我吃下去后啥事没有(能量非负),就看下一个药。如果吃完能量为负,为了让我们吃药的数量尽可能多,我们开始反悔,我们把之前吃过的毒药(会减能量的药)和当前做比较,这里我们可以用一个最小堆来维护之前吃过的毒药,此时堆顶为吃过的毒药中减的最多的,如果当前药比堆定大(也就是减的少,因为是负数),那我们就把堆顶,这个吃过的药,吐出来(能量加回去),吃下新的毒药(减当前的毒药)
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;
//qdu打铁匠
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
priority_queue<int,vector<int>,greater<int> >q;
int main()
{int n;n=read();int tot=0; ll ph=0;for(int i=1;i<=n;i++){int x=read();if(x>=0){tot++;ph+=x;}else {if(ph+x>=0){ph+=x;q.push(x);tot++;}else {if(!q.empty()&&x>q.top()){ph-=q.top();q.pop();q.push(x);ph+=x;}}}}cout<<tot;
}
简单代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;
//qdu打铁匠
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int INF=0x3f3f3f3f;
const int maxn=3e3+9;
int a[maxn];
ll dp[maxn];
int w[maxn];
int main()
{int n=read();for(int i=1;i<=n;i++){cin>>a[i];}memset(dp,-INF,sizeof(dp));dp[0]=0;for(int i=1;i<=n;i++){for(int j=i;j>0;j--){if(dp[j-1]+a[i]>=0){dp[j]=max(dp[j],dp[j-1]+a[i]);}}}for(int i=n;i>=0;i--){if(dp[i]>=0){cout<<i<<endl;return 0; }}
}