BZOJ4977 跳伞求生(贪心)
如果现在选定了一些要求消灭的敌人而不考虑积分,显然应该让每个敌人被刚好能消灭他的人消灭。再考虑最大化积分,显然我们应该优先消灭ci-bi大的敌人,所选用的a也应尽量大。于是按ci-bi从大到小排序,用一个multiset维护a,每次看其中是否有能消灭该敌人的人,如果有则将最小的删去,并用选中的Σci-bi及从大到小选ai更新答案。注意按这种方式将所有能消灭的人都消灭并不一定是最优的,比如这组数据。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<set> using namespace std; #define ll long long #define N 100010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N]; ll ans,tot; multiset<int> f; struct data { int x,y; bool operator <(const data&a) const { return y>a.y; } }b[N]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj4977.in","r",stdin); freopen("bzoj4977.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) f.insert(a[i]=read()); sort(a+1,a+n+1),reverse(a+1,a+n+1); for (int i=1;i<=m;i++) b[i].x=read(),b[i].y=read()-b[i].x; sort(b+1,b+m+1); int cnt=0; for (int i=1;i<=m;i++) { multiset<int>::iterator it=f.lower_bound(b[i].x+1); if (it!=f.end()) { ans=max(ans,tot+=a[++cnt]+b[i].y); f.erase(it); } } cout<<ans; return 0; }