[关闭]
@wsndy-xx 2018-05-13T17:30:58.000000Z 字数 1857 阅读 1070

Luogu p1174

题解


贪心 + dp

对于最下面一行是 的砖块可以免费打掉
对于 交叉的地方,now[] 存储将 上面全部的 的总分累积在 的位置, res[] 存储每一列的前缀和,最后 now[] 要加上 ret[],表示该点以下所有的点都选了,并且该点上面连续的免费砖块也都打掉了
预处理 ci[i][j] 表示在 i 列打掉前 j 个砖块所需要的子弹。
分组背包思想: dp[j][i] 表示前j列总共耗费i个子弹,且之后不用”借”子弹,dp[i][j][1] 表示之后还要”借“子弹,所能得到的最大分数(“借”的意思:比如第一列是 2 Y 2 N 且N必须先打掉,那么 dp[1][1][0]=2,dp[1][1][1]=4),答案即为 dp[m][k][0].
状态转移方程: dp[j][k][0]=max(dp[j][k][0],max(dp[j-1][k-ci[j][i]][1],dp[j-1][k-ci[j][i]][0])+res[j][i]);
dp[j][k][0]=max(dp[j][k][0],dp[j-1][k-ci[j][i]][0]+now[j][i]);
dp[j][k][1]=max(dp[j][k][1],dp[j-1][k-ci[j][i]][1]+now[j][i]);

初始化: for(j=0;j<=m;j++) dp[j][0][0]=-inf;

Code

  1. #include <cmath>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <iostream>
  5. #include <algorithm>
  6. #define LL long long
  7. #define M(a) memset(a, 0, sizeof a)
  8. using namespace std;
  9. const int N = 205;
  10. int n, m, p, ans;
  11. char ch;
  12. int a[N][N], whe[N], res[N][N];
  13. int dp[N][N][2], ci[N][N], now[N][N]; //0:不需要借,1:需要借
  14. bool b[N][N];
  15. int main() {
  16. scanf("%d%d%d",&n,&m,&p);
  17. if(p == 0) {printf("0\n"); return 0;}
  18. for(int i = n; i >= 1; i --)
  19. for(int j = 1; j <= m; j ++) {
  20. scanf("%d", &a[i][j]);
  21. cin >> ch;
  22. if(ch == 'Y') b[i][j] = 1;
  23. }
  24. for(int j = 1; j <= m; j ++)
  25. for(int i = 1; i <= n; i ++) {
  26. if(!b[i][j]) {whe[j] = i; break;}
  27. ans += a[i][j];
  28. }
  29. for(int j = 1; j <= m; j ++)
  30. for(int i = whe[j]; i <= n; i ++)
  31. res[j][i] = res[j][i - 1] + a[i][j];
  32. for(int j = 1; j <= m; j ++)
  33. for(int i = whe[j]; i <= n; i ++)
  34. now[j][i] = res[j][i];
  35. for(int j = 1; j <= m; j ++) {
  36. ci[j][whe[j]] = 1;
  37. for(int i = whe[j]; i <= n; i ++) {
  38. int tmp = i;
  39. while(b[i + 1][j]) i ++;
  40. now[j][tmp] += res[j][i] - res[j][tmp];
  41. ci[j][i + 1] = ci[j][tmp] + 1;
  42. }
  43. }
  44. for(int j = 0; j <= m; j ++) dp[j][0][0] = -1e8;
  45. for(int j = 1; j <= m; j ++)
  46. for(int k = 1; k <= p; k ++) {
  47. dp[j][k][0] = max(dp[j][k][0], dp[j - 1][k][0]);
  48. dp[j][k][1] = max(dp[j][k][1], dp[j - 1][k][1]);
  49. for(int i = whe[j]; i <= n; i ++)
  50. if(!b[i][j] && k >= ci[j][i]) {
  51. dp[j][k][0] = max(dp[j][k][0], max(dp[j - 1][k - ci[j][i]][1], dp[j - 1][k - ci[j][i]][0]) + res[j][i]);
  52. dp[j][k][0] = max(dp[j][k][0], dp[j - 1][k - ci[j][i]][0] + now[j][i]);
  53. dp[j][k][1] = max(dp[j][k][1], dp[j - 1][k - ci[j][i]][1] + now[j][i]);
  54. }
  55. }
  56. printf("%d\n",dp[m][p][0] + ans);
  57. return 0;
  58. }

参考

参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注