Description
![](https://i-blog.csdnimg.cn/blog_migrate/6b8a46e859e4f93031a78ee165e2af9d.png)
Input
![](https://i-blog.csdnimg.cn/blog_migrate/60494c27c8b256512faf90b185a61c48.png)
Output
![](https://i-blog.csdnimg.cn/blog_migrate/f069c003ed00b8dab2f525f01e772dd2.png)
Sample Input
Sample 1: 2 15 3 2 5 3 Sample 2: 3 70 71 100 69 1 1 2
Sample Output
Sample 1: 10 Sample 2: 140
Data Constraint
![](https://i-blog.csdnimg.cn/blog_migrate/fd9af8628febb7e5c820257b38d2db3e.png)
分析
这题终于用到了当年我学背包的时候想到过的贪心思想了
首先有用的物品不超过100个,如果a相同只要b最大的
然后有引理:给定n个整数,其中任意整数的和一定为n的倍数
然后我们将物品的性价比排序,如果性价比相同要体积小一点的
然后我们考虑背包的一大部分空间用性价比最高的物品填充,那么填充多少呢?
引理:其他非性价比最高的物品的个数<性价比最高的物品体积
因为当上面的符号变成≥时,一定有一部分体积的和是性价比最高体积的倍数,用它替换不会变劣
所以就要填充$\left \lfloor \frac{m}{a_{best}} \right \rfloor -100$个性价比最高物品
剩下做完全背包即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; typedef long long ll; const int N=1e5+10; struct Item { ll a,b; }t[20*N]; int n,n1; ll f[N],ans,lans,m; bool CMP(Item a,Item b) {return a.b*b.a>b.b*a.a||a.b*b.a==b.b*a.a&&a.a<b.a;} bool CMP1(Item a,Item b) {return a.a<b.a||a.a==b.a&&a.b<b.b;} int main() { freopen("backpack.in","r",stdin); freopen("backpack.out","w",stdout); scanf("%d%lld",&n,&m); for (int i=1;i<=n;i++) scanf("%lld%lld",&t[i].a,&t[i].b); sort(t+1,t+n+1,CMP1);n1=n;n=0; for (int i=1;i<=n1;i++) if (t[i].a!=t[i+1].a) t[++n]=t[i]; sort(t+1,t+n+1,CMP); if (m/t[1].a>=100ll) ans=(m/t[1].a-100ll)*t[1].b,m-=((m/t[1].a)-100ll)*t[1].a; for (int i=0;i<=m;i++) for (int j=1;j<=n;j++) if (i+t[j].a<=m) f[i+t[j].a]=max(f[i+t[j].a],f[i]+t[j].b); for (int i=0;i<=m;i++) lans=max(lans,f[i]); printf("%lld\n",ans+lans); }