nyoj-746

整数划分(四)

时间限制:1000 ms  |  内存限制:65535 KB
难度:3
 
描述

       暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷。。亲爱的你能帮帮他吗?

      问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积

 
输入
第一行是一个整数T,表示有T组测试数据
接下来T行,每行有两个正整数 n,m ( 1<= n < 10^19, 0 < m <= n的位数);
输出
输出每组测试样例结果为一个整数占一行
样例输入
2
111 2
1111 2
样例输出
11
121
来源
经典题目
上传者
TC_胡仁东
区间dp。
开始我被样例忽悠了,以为所有的整数都是1111....这种形式的,后来才知道并不是。

根据区间dp的思想,我们定义dp [ i ] [ j ]为从开始到 i 中加入 j 个乘号得到的最大值。

那么我们可以依次计算加入1----m-1个乘号的结果

而每次放入x个乘号的最大值只需枚举第x个乘号的放的位置即可

dp [ i ] [ j ]  = max(dp [ i ] [ j ] , dp [ k ] [ j-1 ] * a [ k] [ i - 1]);

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define repu(i, a, b) for(int i = a; i < b; i++)
#define repd(i, a, b) for(int i = b; i >= a; i--)
#define sfi(n) scanf("%d", &n)
#define pfi(n) printf("%d
", n)
#define _cle(m, a) memset(m, a, sizeof(m))
ll a[20][20];
ll dp[20][20];
char s[21];
int n, k;
void init()
{
    _cle(a, 0);
    repu(i, 0, n) repu(j, i, n) repu(k, i, j + 1)
        a[i][j] = a[i][j] * 10ll + (ll)(s[k] - '0');
}

int main()
{
    int T;
    sfi(T);
    while(T--)
    {
        _cle(dp, 0);
        scanf("%s", s);
        n = strlen(s);
        init();
        sfi(k); k--;
        repu(i, 1, n + 1)
        {
            dp[i][0] = a[0][i - 1];
            repu(j, 1, k + 1) repu(p, 1, i)
                dp[i][j] = max(dp[i][j], dp[p][j - 1] * a[p][i - 1]);
        }
        printf("%lld
", dp[n][k]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sunus/p/4777029.html