题意 : 设 NUM 是一个 n 位十进制整数。如果将 NUM 划分为 k 段,则可得到 k 个整数。这 k 个整数的乘积称为 NUM 的一个 k 乘积。试设计一个算法,对于给定的 NUM 和 k,求出 NUM 的最大 k 乘积

分析 :

定义 dp[i][j] = 前 i 个数字中间插入 j 个乘号时候的最大乘积是多少

初始化 dp[ i ][ 0 ] = NUM(1, i)  1 <= i <= len(NUM)

最后的结果则存于 dp[n][k]

状态转移方程为 dp[i][j] = max( dp[i][j] ,  dp[m][j-1] * NUM[m+1 ~ i] )   j-1 < m < i

注 : NUM[a~b] 表示 NUM 的第 a 位到第 b 位组成的数字

关于状态转移方程先来看一个例子 n = 4、k = 2、NUM = 1231

首先初始化

dp[1][0] = 1

dp[2][0] = 12

dp[3][0] = 123

dp[4][0] = 1231

然后安插 1 个乘号的时候各个长度的最大乘积

dp[2][1] = dp[1][0] * 2 = 2

dp[3][1] = max( dp[1][0]*23、dp[2][0]*3 ) = 36

dp[4][1] = max( dp[1][0]*231、dp[2][0]*31、dp[3][0]*1 ) = 372

接着是安插 2 个乘号的时候

dp[3][2] = dp[2][1] * 3 = 6

dp[4][2] = max( dp[2][1]*31、dp[3][1]*1 ) = 62

细细去推一下这个例子,可能就会发现更加理解了这个 dp

可以看出这个 dp 定义的第二维应该是阶段、而第一维是 dp 的状态

换句话说只有知道在各个长度安插 1 个乘号的结果才能推出各个长度安插 2 个乘号的结果

C++版

#include<bits/stdc++.h>
#define LL long long
using namespace std;
;
LL dp[maxn][maxn];
char num[maxn];

LL GetVal(int st, int en)
{
    LL ret = ;
    for(int i=st; i<=en; i++)
        ret = ret *  + (num[i] - ');
    return ret;
}

int main(void)
{
    int n, k;
    while(~scanf("%d %d", &n, &k)){
        scanf());
        ; i<=n; i++)
            dp[i][] = GetVal(, i);

        ; j<=k-; j++)
            ; i<=n; i++)
                for(int m=j; m<i; m++)
                    dp[i][j] = max(dp[i][j], dp[m][j-]*GetVal(m+, i));

        printf(]);
    }
    ;
}

JAVA大数版

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.math.*;
import java.util.Arrays;
public class Main {
    static BigInteger[][] dp = new BigInteger[15][15];
    public static void main(String[] args){
        Scanner cin = new Scanner (new BufferedInputStream(System.in));

        int n, k;
        String s;

        while(cin.hasNext()){
            n = cin.nextInt();
            k = cin.nextInt();

            s = cin.next();
            for(int i=1; i<=n; i++){
                dp[i][0] = BigInteger.valueOf( Integer.parseInt(s.substring(0,i)) );
                //System.out.println(dp[i][0]);
            }

            for(int j=1; j<=k-1; j++)
                for(int i=j+1; i<=n; i++){
                    dp[i][j] = BigInteger.ZERO;
                    for(int m=j; m<i; m++){
                        if(dp[i][j].compareTo(dp[m][j-1].multiply( BigInteger.valueOf( Integer.parseInt(s.substring(m, i)) ) )) < 0)
                            dp[i][j] = dp[m][j-1].multiply( BigInteger.valueOf( Integer.parseInt(s.substring(m, i)) ) );
                    }
                }

            System.out.println(dp[n][k-1]);
        }
    }
}

最大 k 乘积问题 ( 经典区间DP )的更多相关文章

  1. POJ 1160 经典区间dp/四边形优化

    链接http://poj.org/problem?id=1160 很好的一个题,涉及到了以前老师说过的一个题目,可惜没往那上面想. 题意,给出N个城镇的地址,他们在一条直线上,现在要选择P个城镇建立邮 ...

  2. poj 1390 Blocks (经典区间dp 方块消除)

    Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4250   Accepted: 1704 Descriptio ...

  3. 蓝桥杯 乘积最大(区间dp、数据水的话long long,暴力就能过)

    Description 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋 ...

  4. ZOJ 3541 The Last Puzzle(经典区间dp)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3541 题意:有一排开关,有个开关有两个值t和d,t是按下开关后在t秒后会自 ...

  5. nyoj 737 石子合并 经典区间 dp

    石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆 ...

  6. 51nod 1021 石子归并 - 区间dp(经典)

    题目地址:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1021 经典区间dp,dp[i][j] 表示将从 i 到 j 堆 ...

  7. 区间dp实战练习

    题解报告:poj 2955 Brackets(括号匹配) Description We give the following inductive definition of a “regular br ...

  8. [NYIST15]括号匹配(二)(区间dp)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=15 经典区间dp,首先枚举区间的大小和该区间的左边界,这时右边界也可计算出来.首先初 ...

  9. 题解报告:NYOJ #737 石子合并(一)(区间dp)

    描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值 ...

随机推荐

  1. SSLPinning简介,使用Xposed+JustTrustMe来突破SSL Pinning

    0x00 前面 如果你是一干Web安全的,当你在测试目前大多数的手机APP应用程序时,你一定遇到过burpsuite无法抓到数据包的情况,开始你以为只是https的问题,但是当你使用了burpsuit ...

  2. 13.DoS防御----BeEF浏览器渗透----暴力破解之美杜莎---DNS指南

    DoS防御 启用ICMP,UDP,TCP泛洪过滤 登录路由器管理后台 高级-安全部分 BeEF浏览器渗透 用kali进行客户端攻击 钓鱼攻击 打开beef 浏览器打开beef cd /usr/shar ...

  3. DataAdapter的Fill方法(转)

    使用DataAdapter填充DataSet(1) 在选择了DataAdapter的类型(SqlDataAdapter或OleDbDataAdapter)并配置了DataAdapter来执行所需的任务 ...

  4. 联想Z485安装64位ubantu

    开始今天的正式写作之前不得不吐槽一下联想电脑,真的是很垃圾!联想Z485使用的是AMD的处理器,性能差的很,更让人不能忍的是,居然不能正常安装64位ubantu.这个情况让那些想在自己笔记电脑上安装T ...

  5. mybatis源码级别深度剖析

    mybatis 3.x源码深度解析与最佳实践 Mybatis源码解析优秀博文

  6. [Git] 014 远程仓库篇 第一话

    0. 前言 在 [Git] 001 初识 Git 与 GitHub 之新建仓库 中,我在 GitHub 上建了一个仓库 "interesting" 这回的任务 把远程的 " ...

  7. exists、in和join比较

    这个根据实际情况具体分析 遇到问题了再具体分析就行.

  8. python之optparse

    Python有两个内建的模块用来处理命令行参数 一个是getopt只能简单处理命令行参数 一个是optparse,功能更强大,而且易于使用,可以方便地生成标准的,符合Unix/Posix规范的命令行说 ...

  9. GUI程序原理分析

    1,Qt 是一套跨平台的程序设计库,这套程序设计库主要用于 GUI 方面的程序设计开发,所以本系列博文主要是利用C++介绍 GUI 程序设计技术: 2,命令行应用程序: 1,命令行应用程序的特点(Co ...

  10. 对C++拷贝构造函数的一点理解

    一. 什么是拷贝构造函数 先看一个简单的例子: #include <iostream> using namespace std; class CExample { private: int ...