洛谷P1018 乘积最大
? 解题记录 ? ? 洛谷 ? ? 动态规划 ?    2017-07-24 23:20:59    765    0    0

题目描述

今年是国际数学联盟确定的“2000――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:

    设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:

有一个数字串:312, 当N=3,K=1时会有以下两种分法:

1) 3*12=36

2) 31*2=62

这时,符合题目要求的结果是:31*2=62

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。

输入输出格式

输入格式:

 

程序的输入共有两行:

第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)

第二行是一个长度为N的数字串。

 

输出格式:

 

结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。

 

输入输出样例

输入样例#1:
4  2
1231
输出样例#1: 
62
 

        突然发现博客没DP题啊,然后就现水了一道占个位置。

        一道经典的DP。首先,我们确定当前状态dp[i][j]表示 放的乘号个数为i、放到了第j个数字。

        然后考虑转移方程。首先我们可以这样想,一个长度为j的序列当没有加入一个乘号时向其中加

        入一个乘号是可以用O(N) 时间枚举最优解的(只用枚举乘号位置)。那么我们是不是可以考虑

        用这种方法对于每一组K相同的状态,枚举出长度为j(j -> 1~N)的每一种最优解呢?因为我每一

        次枚举K时对于前面的dp[K-1]的一组状态已经保证为最优解了。于是我们就有了状态转移方程:

                     dp[j][i]=max{dp[k][i-1]*num[k+1][j]};(1<=i<=K ;1<=j<=N;1<=k<=j)

    其中num[a][b]表示从下标a到b的数字组成的数的大小(对于1231  num[2][4]=231)        时间复杂度O(N^2*m)        另外,一看到这道题本来应该是用高精度的,结果不知道为什么数据太水,Long Long就水过了。        对于恶心的long long 的读入,屈服于iostream黑恶势力……

#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=40;
ll num[maxn][maxn]={ };
ll dp[maxn][20]={ };
int n,m;
char s[50];

void init(int n){
    memset(num,0,sizeof(num));
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
        num[i][i]=1LL*(s[i-1]-'0');
    for(int i=1;i<=n-1;i++){
        for(int j=i+1;j<=n;j++){
            ll id=1LL*(s[j-1]-'0');
            num[i][j]=num[i][j-1]*10+id;
        }
    }
}

int main(){
    cin>>n>>m;
    cin>>s;
    init(n);
    for(int i=1;i<=n;i++)
        dp[i][0]=num[1][i];
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++)
            for(int k=1;k<=j;k++)
                if(dp[k][i-1]*num[k+1][j]>dp[j][i])
                    dp[j][i]=dp[k][i-1]*num[k+1][j];
    }
    cout<<dp[n][m];
    return 0;
}

----------+--------+------18/3/27------+--------+--------

洛谷数据加强了QAQ……这里挂一个大整形高精度:

#include<cstring>
#include<algorithm>
using namespace std;
namespace BIGINT {
 #define LL long long
 struct INT1024 {
     int len;
     int s[1030];
     INT1024() {clean();}
     void clean() {memset(s, 0, sizeof(s)), len = 0;}
     void operator = (int x) {
         for(; x; x /= 10) s[len++] = x % 10;
     }
     void print() {
         for(int i = len - 1; i >= 0; --i) printf("%d", s[i]);
         putchar('\n');
     }
 };
 INT1024 c;
 INT1024 operator + (INT1024 a, INT1024 b) {
     int len = max(a.len, b.len);
     c.clean();
     c.len=len;
     for(int i = 0;i < len; ++i) c.s[i] = a.s[i] + b.s[i];
     for(int i = 0;i < len; ++i) c.s[i + 1] += c.s[i] / 10, c.s[i] %= 10;
     if(c.s[len]) ++c.len;
     return c;
 }
 INT1024 operator - (INT1024 a, INT1024 b) {
     c.clean();
     for(int i = 0; i < a.len; ++i) {
         c.s[i] += a.s[i] - b.s[i];
         if(c.s[i] < 0) c.s[i] += 10, --a.s[i + 1];
     }
     int len = a.len - 1;
     for(; !c.s[len]; --len);
     c.len = len + 1;
     return c;
 }
 INT1024 operator * (INT1024 a, INT1024 b) {
     int len = a.len + b.len - 1;
     c.clean();
     c.len = len;
     for(int i = 0;i < a.len; ++i) 
 for(int j = 0; j < b.len; ++j) 
 c.s[i + j] += a.s[i] * b.s[j];
     for(int i = 0;i < len; ++i) c.s[i + 1] += c.s[i] / 10, c.s[i] %= 10;
     if(c.s[len]) ++c.len;
     return c;
 }
}
 ​


上一篇: 洛谷P1525 关押罪犯

下一篇: BZOJ2049 洞穴勘测

765 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航