CF1203F2 Complete the Projects

一、题目

点此看题

二、解法

首先上分和掉分分开来考虑,可以先上分,上分一定是贪心地从 a a a最小的开始上分(如果不行直接跳出)

降分咋一看不好处理,能不能也排序呢?下面我们来推导一下:

假设 1 , 2 1,2 1,2都要选取,设现在的rating r r r。如果 1 1 1先选,那么 r ≥ max ⁡ ( a 1 , a 2 − b 1 ) r\geq\max(a_1,a_2-b_1) rmax(a1,a2b1),如果 2 2 2先选,那么 r ≥ max ⁡ ( a 2 , a 1 − b 2 ) r\geq\max(a_2,a_1-b_2) rmax(a2,a1b2)

假设先选 1 1 1更优(也就是限制更松),那么 max ⁡ ( a 1 , a 2 − b 1 ) ≤ max ⁡ ( a 2 , a 1 − b 2 ) \max(a_1,a_2-b_1)\leq\max(a_2,a_1-b_2) max(a1,a2b1)max(a2,a1b2),由于 a 1 − b 2 ≥ a 1 a_1-b_2\geq a_1 a1b2a1 a 2 − b 1 ≥ a 2 a_2-b_1\geq a_2 a2b1a2,所以最大值的比较转化成了: a 2 − b 1 ≤ a 1 − b 2 a_2-b_1\leq a_1-b_2 a2b1a1b2,也就是:
a 2 + b 2 ≤ a 1 + b 1 a_2+b_2\leq a_1+b_1 a2+b2a1+b1所以我们得到了应该先选 a + b a+b a+b最大的,由于不知道选什么,所以我们需要跑背包,注意背包是倒着往上还原的,所以要先选 a + b a+b a+b大的应该把它放在最后面,综上按 a + b a+b a+b从小到大排序(如果你觉得有点抽象可以结合样例 1 1 1理解)

#include 
#include 
#include 
using namespace std;
const int M = 105;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k1,k2,ans,dp[60005];
struct node
{
	int a,b;
}s1[M],s2[M];
bool cmp1(node x,node y)
{
	return x.a<y.a;
}
bool cmp2(node x,node y)
{
	return x.a+x.b<y.a+y.b;
}
signed main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		int a=read(),b=read();
		if(b>=0) s1[++k1]=node{a,b};
		else s2[++k2]=node{a,b};
	}
	sort(s1+1,s1+1+k1,cmp1);
	for(int i=1;i<=k1;i++)
	{
		if(m<s1[i].a) break;
		m+=s1[i].b;ans++;
	}
	sort(s2+1,s2+1+k2,cmp2);
	for(int i=1;i<=k2;i++)
	{
		for(int j=m;j>=0;j--)
			if(j>=s2[i].a && j+s2[i].b>=0)
				dp[j]=max(dp[j],dp[j+s2[i].b]+1);
	}
	printf("%d\n",ans+dp[m]);
}

你可能感兴趣的:(贪心,dp)