原题链接

考察:背包dp

思路:

       luogu题解的300分界线的题解本蒟蒻完全看不懂 .这篇题解是自己对第一篇题解的理解.

      首项观察数据范围可以发现此范围MLE,需要压缩范围.根据极差<=3.可以将体积范围压成1~4.

      但是!这道题不能把m根据vi压缩体积,根据vi的压缩不同,会导致m得到不同的取值,使得结果偏大或偏小.

      那么此题关于体积的限制只能将压缩后的体积->原体积才能求解.每个vi-(min(vi)-1).原体积就是V压缩后+k(选了几个)*minv <=m.

      所以需要f[i][j][k]前i个体积压缩后为j时,选了k个的最大重要度和.注意这道题状态转移需要条件j压缩后+k(选了几个)*minv <=m.如果j要符合条件,就需要枚举j等于前i个中k个的压缩后体积和.所以j的范围是p[i].first~sum.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 110,M = 410;
 7 typedef long long LL;
 8 typedef pair<int,int> PII;
 9 int n,m,f[M][N],ans;
10 LL sum;
11 PII p[N];
12 int main() 
13 {
14     scanf("%d%d",&n,&m);
15     for(int i=1;i<=n;i++)//m不能减去n*(p1-1)因为不是全部买 
16         scanf("%d%d",&p[i].first,&p[i].second),sum+=p[i].first;
17     sort(p+1,p+n+1);
18     int s = p[1].first-1;
19     sum-=p[1].first*n;
20     for(int i=1;i<=n;i++) p[i].first-=s;
21     for(int i=1;i<=n;i++)
22       for(int j=sum;j>=p[i].first;j--)
23         for(int k=1;k<=i;k++)
24           if(j<=m-k*s)  f[j][k] = max(f[j-p[i].first][k-1]+p[i].second,f[j][k]);
25     for(int i=sum;i>=0;i--)
26       for(int k=1;k<=n;k++) ans = max(f[i][k],ans);
27     printf("%d\n",ans);
28     return 0;
29 }