2 solutions
-
4
#P8548. 小挖的买花
我像是小挖的nigger一样题意
每次用有限的钱买花,要求花足够新鲜,在此条件下选最美的那组花。
思路
由于钱是有限的,花又要足够新鲜,所以可以当做二维费用做
钱的上限已给出,新鲜度的上限可以当所有花的新鲜度之和
所以
#include<bits/stdc++.h> using namespace std; int n,q,cost[510],fr[510],be[510],c,f,dp[510][250010],sum,maxbe; int main(){ cin>>n>>q; for(int i=1;i<=n;i++){ cin>>cost[i]>>fr[i]>>be[i]; sum+=fr[i];//计算新鲜度上限 } for(int i=1;i<=q;i++){ maxbe=0; cin>>c>>f; for(int j=c;j>=0;j--){ for(int k=sum;k>=0;k--){ dp[j][k]=INT_MIN;//初始化dp数组 } } dp[0][0]=0; for(int j=1;j<=n;j++){ for(int k=c;k>=cost[j];k--){ for(int l=sum;l>=fr[j];l--){ //遍历二维费用 if(dp[k-cost[j]][l-fr[j]]!=INT_MIN){ dp[k][l]=max(dp[k-cost[j]][l-fr[j]]+be[j],dp[k][l]); } if(f<=l){ maxbe=max(maxbe,dp[k][l]); } } } } cout<<maxbe<<endl; } return 0; }
但是40WA,其他全部TLE
注意到q的数据范围:1≤q≤106
这种情况下,我们必须将查询的时间复杂度降为O(1)
所以要预处理dp和最大值数组
代码如下
#include<iostream> #include<climits> using namespace std; int n,q,cost[510],fr[510],be[510],c,f,dp[510][21210],sum,maxbe[510][250010]; int main(){ cin>>n>>q; for(int i=1;i<=n;i++){ cin>>cost[i]>>fr[i]>>be[i]; sum+=fr[i];//计算新鲜度上限 } for(int j=505;j>=0;j--){ for(int k=sum;k>=0;k--){ dp[j][k]=INT_MIN;//初始化dp数组 } } dp[0][0]=0; //预处理dp数组 for(int j=1;j<=n;j++){ for(int k=505;k>=cost[j];k--){ for(int l=sum;l>=fr[j];l--){ if(dp[k-cost[j]][l-fr[j]]!=INT_MIN){ //遍历二维费用 dp[k][l]=max(dp[k-cost[j]][l-fr[j]]+be[j],dp[k][l]); } } } } //前缀和预处理最大值数组 for(int i=0;i<=505;i++){ for(int j=0;j<=sum;j++){ if(i==0)maxbe[i][j]=dp[i][j]; else maxbe[i][j]=max(dp[i][j],maxbe[i-1][j]); } } for(int i=0;i<=505;i++){ for(int j=sum-1;j>=0;j--){ maxbe[i][j]=max(maxbe[i][j],maxbe[i][j+1]); } } for(int i=1;i<=q;i++){ cin>>c>>f; if(f>sum)cout<<0<<endl; else cout<<max(maxbe[c][f],0)<<endl; } return 0; }
但是80WA,还是有两个测试用例TLE
注意到3≤n≤500,0≤cost,fr,cj≤500
也就是说sum最大为5002
那么预处理时间复杂度......
6.25*1010!!!!!
所以还要降预处理时间复杂度
怎么降呢?
这时我们发现:0≤f≤500
在要求新鲜度小于等于500的情况下,500以上的新鲜度数组没有任何用处
所以我们可以在遍历每一朵花的时候,将上一朵花大于500的新鲜度存进500新鲜度的dp数组里
由于:0≤f≤500
所以我们可以将内层循环改为500+500=1000
代码如下:
#include<iostream> #include<climits> using namespace std; int n,q,cost[510],fr[510],be[510],c,f,dp[510][1010],sum,maxbe[510][1010];//数组第二维大小改为1010 int main(){ cin>>n>>q; for(int i=1;i<=n;i++){ cin>>cost[i]>>fr[i]>>be[i]; sum+=fr[i];//计算新鲜度最大值 } for(int j=505;j>=0;j--){ for(int k=1000;k>=0;k--){ dp[j][k]=INT_MIN;//初始化dp数组 } } dp[0][0]=0; for(int j=1;j<=n;j++){ for(int k=505;k>=cost[j];k--){ for(int l=1000;l>=fr[j];l--){ //内层循环改为1000,正常二维费用 if(dp[k-cost[j]][l-fr[j]]!=INT_MIN){ dp[k][l]=max(dp[k-cost[j]][l-fr[j]]+be[j],dp[k][l]); } } } for(int k=505;k>=cost[j];k--){ for(int l=1000;l>=500;l--){ dp[k][500]=max(dp[k][500],dp[k][l]);//将大于500的新鲜度存进500里 } } } //前缀和预处理最大值数组(由于dp数组内层循环改为1000,所以可以在处理最大值时也将内层循环改为1000) for(int i=0;i<=505;i++){ for(int j=0;j<=1000;j++){ if(i==0)maxbe[i][j]=dp[i][j]; else maxbe[i][j]=max(dp[i][j],maxbe[i-1][j]); } } for(int i=0;i<=505;i++){ for(int j=999;j>=0;j--){ maxbe[i][j]=max(maxbe[i][j],maxbe[i][j+1]); } } for(int i=1;i<=q;i++){ cin>>c>>f; if(f>sum)cout<<0<<endl; else cout<<max(maxbe[c][f],0)<<endl; } return 0; }
比老师的方法简单
-
0
/* input1 16 16 13 190 150519 487 278 963895 311 445 999567 277 277 656425 82 232 970123 351 64 393056 492 468 329210 370 123 446733 190 452 542659 86 226 511286 14 43 855461 98 283 14229 355 145 418112 341 478 179540 246 263 518758 280 468 664876 322 288 87 400 352 117 282 162 344 411 464 143 221 141 172 268 183 5 450 328 288 67 361 59 152 242 250 324 6 73 458 145 output1 2518762 0 2518762 2487389 2518762 3030048 2487389 1976103 2336870 3030048 2487389 2518762 1976103 2487389 0 3030048 input2 2 3 1 1 1 2 2 2 3 4 3 3 3 2 output2 0 3 3 */ //典型的限制性二维费用01背包问题.对于限制最小值操作,空间消耗无法确定,如果直接开肯定 MLE //将 ≥500 的新鲜度所带来的最优方案都存放到 501 的新鲜度中 //q≤1E6,我们要做到 O(1) 查询(易错点:这涉及区间查询,注意不是单点查询!!!),我们就要统计前缀最大值(当前花费c可以取更少c的最优值)和后缀最大值(当前新鲜度f可以取更高f的最优值)。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <algorithm> #include <climits> //#define MAX_N 5 //#define MAX_COST 5 //#define MAX_FR 5 #define MAX_N 501 #define MAX_COST 501 #define MAX_FR 501 int cost[MAX_N], fr[MAX_N], be[MAX_N]; using namespace std; int main() { int n, q; scanf("%d %d", &n, &q); for (int i = 1; i <= n; ++i) scanf("%d %d %d", &cost[i], &fr[i], &be[i]); // Dynamic programming table: dp[c][f] = maximum beauty sum for cost c and freshness f int dp[MAX_COST][MAX_FR]; // memset(dp, 0, sizeof(dp));//本题都是正数,比较方便,极小值ninf是0 for(int c = 0; c < MAX_COST; ++c){ for(int f = 0; f < MAX_FR; ++f){ dp[c][f]=INT_MIN; } } dp[0][0]=0; for (int i = 1; i <= n; ++i) { int c = cost[i]; int f = fr[i]; int b = be[i]; for(int j = MAX_COST - 1; j >= c; --j){ for(int k = MAX_FR - 1; k >= MAX_FR - f - 1; --k){//限制性最小值阈值特殊处理:将>=500的都视为500处理,k取值范围为[MAX_FR - f - 1, MAX_FR - 1]时加上f必然>=MAX_FR - 1 dp[j][MAX_FR - 1] = max(dp[j][MAX_FR - 1], dp[j-c][k] + b); } for(int k = MAX_FR - 2; k >= f; --k){//正常二维费用 dp[j][k] = max(dp[j][k], dp[j-c][k-f] + b); } } } // for(int c = 0; c < 5; ++c){ // for(int f = 0; f < 5; ++f){ // printf("%4d ", dp[c][f]); // } // printf("\n"); // } // Precompute the maximum beauty for each cost and minimum freshness int max_beauty[MAX_COST][MAX_FR]; memset(max_beauty, 0, sizeof(max_beauty)); for(int c = 0; c < MAX_COST; ++c){ max_beauty[c][MAX_FR - 1] = dp[c][MAX_FR - 1]; for(int f = MAX_FR - 2; f >= 0; --f){ max_beauty[c][f]=max(dp[c][f], max_beauty[c][f+1]); } } for(int f = MAX_FR - 1; f >= 0; --f) max_beauty[0][f]=max(max_beauty[0][f], 0); for(int c = 1; c < MAX_COST; ++c){ for(int f = MAX_FR - 1; f >= 0; --f){ max_beauty[c][f]=max(max_beauty[c][f], max_beauty[c-1][f]); } } while(q--){ int C, F; scanf("%d %d", &C, &F); printf("%d\n", max_beauty[C][F]); } return 0; }/* input1 16 16 13 190 150519 487 278 963895 311 445 999567 277 277 656425 82 232 970123 351 64 393056 492 468 329210 370 123 446733 190 452 542659 86 226 511286 14 43 855461 98 283 14229 355 145 418112 341 478 179540 246 263 518758 280 468 664876 322 288 87 400 352 117 282 162 344 411 464 143 221 141 172 268 183 5 450 328 288 67 361 59 152 242 250 324 6 73 458 145 output1 2518762 0 2518762 2487389 2518762 3030048 2487389 1976103 2336870 3030048 2487389 2518762 1976103 2487389 0 3030048 input2 2 3 1 1 1 2 2 2 3 4 3 3 3 2 output2 0 3 3 */ //典型的限制性二维费用01背包问题.对于限制最小值操作,空间消耗无法确定,如果直接开肯定 MLE //将 ≥500 的新鲜度所带来的最优方案都存放到 501 的新鲜度中 //q≤1E6,我们要做到 O(1) 查询(易错点:这涉及区间查询,注意不是单点查询!!!),我们就要统计前缀最大值(当前花费c可以取更少c的最优值)和后缀最大值(当前新鲜度f可以取更高f的最优值)。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <algorithm> #include <climits> //#define MAX_N 5 //#define MAX_COST 5 //#define MAX_FR 5 #define MAX_N 501 #define MAX_COST 501 #define MAX_FR 501 int cost[MAX_N], fr[MAX_N], be[MAX_N]; using namespace std; int main() { int n, q; scanf("%d %d", &n, &q); for (int i = 1; i <= n; ++i) scanf("%d %d %d", &cost[i], &fr[i], &be[i]); // Dynamic programming table: dp[c][f] = maximum beauty sum for cost c and freshness f int dp[MAX_COST][MAX_FR]; // memset(dp, 0, sizeof(dp));//本题都是正数,比较方便,极小值ninf是0 for(int c = 0; c < MAX_COST; ++c){ for(int f = 0; f < MAX_FR; ++f){ dp[c][f]=INT_MIN; } } dp[0][0]=0; for (int i = 1; i <= n; ++i) { int c = cost[i]; int f = fr[i]; int b = be[i]; for(int j = MAX_COST - 1; j >= c; --j){ for(int k = MAX_FR - 1; k >= MAX_FR - f - 1; --k){//限制性最小值阈值特殊处理:将>=500的都视为500处理,k取值范围为[MAX_FR - f - 1, MAX_FR - 1]时加上f必然>=MAX_FR - 1 dp[j][MAX_FR - 1] = max(dp[j][MAX_FR - 1], dp[j-c][k] + b); } for(int k = MAX_FR - 2; k >= f; --k){//正常二维费用 dp[j][k] = max(dp[j][k], dp[j-c][k-f] + b); } } } // for(int c = 0; c < 5; ++c){ // for(int f = 0; f < 5; ++f){ // printf("%4d ", dp[c][f]); // } // printf("\n"); // } // Precompute the maximum beauty for each cost and minimum freshness int max_beauty[MAX_COST][MAX_FR]; memset(max_beauty, 0, sizeof(max_beauty)); for(int c = 0; c < MAX_COST; ++c){ max_beauty[c][MAX_FR - 1] = dp[c][MAX_FR - 1]; for(int f = MAX_FR - 2; f >= 0; --f){ max_beauty[c][f]=max(dp[c][f], max_beauty[c][f+1]); } } for(int f = MAX_FR - 1; f >= 0; --f) max_beauty[0][f]=max(max_beauty[0][f], 0); for(int c = 1; c < MAX_COST; ++c){ for(int f = MAX_FR - 1; f >= 0; --f){ max_beauty[c][f]=max(max_beauty[c][f], max_beauty[c-1][f]); } } while(q--){ int C, F; scanf("%d %d", &C, &F); printf("%d\n", max_beauty[C][F]); } return 0; }
- 1
Information
- ID
- 8018
- Time
- 1000ms
- Memory
- 512MiB
- Difficulty
- 4
- Tags
- # Submissions
- 101
- Accepted
- 3
- Uploaded By