考察:背包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 }