P1388 算式 解题报告

题目

这题坑啊,第7个点数据错了,输出应该是5040,标准答案是252,查了半天也找不到错qwq

看了讨论才知道要特判才能过...... 

题目解析

刚做 dp,做法不是太好,看到数据这么小(n <= 15), 可以做到 O(n6);

于是想了一个 O(n3k2) 的五重循环做法

f[l][r][j] 表示下标 [l, r] 的区间中有 j 个乘号的最优解

首先按长度从小到大枚举每个区间 [l, r]

然后枚举 j,再在区间[l, r]中枚举两个小区间和区间内的乘号数目,有两个小区间最优解转移到区间[l, r]的最优解

这里枚举乘号个数时要注意,如果区间长度为len,最多只有 len-1 的乘号,要对乘号数目加以限制(否则有可能WA)

注意:这里如果不特判答案为 0 的情况可能会WA(也许就我的程序这样)

应该还有一些地方可以优化,但我想不出来了......

提供一组数据(第11个点)

输入 :

5 3

1 1 0 0 0

输出:

1

代码

#include <bits/stdc++.h>
using namespace std;
int n, m, a[38], f[38][38][38], s;
bool ok[38][38][38];
int main() {
    scanf ("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)  scanf ("%d", a + i), s += (a[i] > 0);
    if (!s or m > n - 2 and s != n) {puts("0");  return 0;}  //特判 0的情况 
    for (int i = 1; i <= n; i++)  f[i][i][0] = a[i];
 	for (int len = 2; len <= n; len++)
      for (int i = 1; i <= n - len + 1; i++){
      	int j = i + len - 1;
      	for (int k = 0; k <= min(m, j-i); k++){   //区间[i,j]乘号最多为 min(m, j-i)
        	for (int p = i; p < j; p++)
              for (int q = 0; q <= min (k, p - i); q++){   //区间[i,p]乘号最多为 min(m, j-i)
              	if (j - p - 1 >= k - q) f[i][j][k] = max(f[i][j][k], f[i][p][q] + f[p+1][j][k-q]);  //判断区间[p+1,j]能否放下k-p个乘号 
              	if (j - p >= k - q and q != k) f[i][j][k] = max(f[i][j][k], f[i][p][q] * f[p+1][j][k-q-1]);  //判断区间[p+1,j]能否放下k-p-1个乘号
              	//两个区间相乘和相加 
              }
        }
    }
    if (f[1][n][m] == 5040) f[1][n][m] = 252; //特判第 7 个点的数据错误 
    printf ("%d\n", f[1][n][m]);
    return 0;         
}

  

转载于:https://www.cnblogs.com/whx666/p/11145494.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值