首先对于 $b>0$ 的工作显然有个贪心,把 $b>0$ 的按 $a$ 从小到大排序
把能做的都做了,然后得到一个最大等级
剩下就是考虑 $b<0$ 的工作了,看到数据显然可以 $O(nr)$ 考虑 $dp$,设 $f[i][j]$ 表示考虑完前 $i$ 个工作,当前等级为 $j$ 时能完成的最大工作数
然后发现这样搞有点问题,因为工作考虑的顺序是会影响到最终答案的,可能先做后面的工作再来做前面的工作可以做两个,但是如果先做前面的再做后面的可能会发现等级不够了...
考虑给所有工作确定一个顺序,使得如果先做 $2$ 不能做 $1$ ,并且先做 $1$ 可以做 $2$ ,则把 $1$ 排在 $2$ 前面考虑
设 $x+b_2<a_1$,$x+b1>=a2$ (注意这里 $b<0$),那么有 $x<a_1-b_2,x>=a_2-b_1$,即 $a_2-b_1<a_1-b_2$
所以排序时根据 $a_1-b_2$ 从大到小排序即可
#include#include #include #include #include #include using namespace std;typedef long long ll;inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f;}const int N=107,M=60007;int n,m;struct dat { int a,b; dat (int _a=0,int _b=0) { a=_a,b=_b; } inline bool operator < (const dat &tmp) const { return a-tmp.b>tmp.a-b; }};vector C,D;inline bool cmp(const dat &A,const dat &B) { return A.a =A.a) m+=A.b,ans++; memset(f,~0x3f,sizeof(f)); f[0][m]=0; int len=D.size(),res=0; for(int i=1;i<=len;i++) { for(int j=0;j<=m;j++) { f[i][j]=f[i-1][j]; if(j-D[i-1].b>=D[i-1].a) f[i][j]=max(f[i][j],f[i-1][j-D[i-1].b]+1); res=max(res,f[i][j]); } } printf("%d\n",ans+res); return 0;}