• RQNOJ 311 [NOIP2000]乘积最大:划分型dp


    题目链接:https://www.rqnoj.cn/problem/311

    题意:

      给你一个长度为n的数字,用t个乘号分开,问你分开后乘积最大为多少。(6<=n<=40,1<=k<=30)

    题解:

      简化问题:

        给原数字之前添加一个"1 *",乘号不计入数量,对答案无影响。

        例如:"1231"可以变成"(1*)1231"。

      表示状态:

        dp[i][j] = max num(最后一个乘号之前的最大乘积)

        i:此时在第i个数的前面添了一个乘号

        j:用了j个乘号

        例1:"(1*)12*31":

          dp[2][1] = 12 (数位从0开始从左向右编号

        例2:"(1*)12*3*1"

          dp[3][2] = 12*3 = 36

      找出答案:

        max dp[i][t] * cal_sec(i,n-1)

        cal_sec(x,y)将数字串中[x,y]这个区间的字符串转化为数字

        例如:设n=4,t=1.

           此时为"(1*)12*31"

           则此时这种方案的乘积为dp[2][1]* "31" = 12*31

      如何转移:

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

        在前面的某一段乘积后面再续上一串数字,达到第i位,用了j个乘号。

        前面的某一段乘积:枚举最后一个乘号在第k个数字之前,用了j-1个乘号。

        要续的数字:从第k位到i-1位 = cal_sec(k,i-1)

      边界条件:

        初始时用了0个乘号,但乘积为1。

        例如:"(1*)1231".

        特判:如果输入的数字就是0,则直接返回0.

      注:输入用string,答案用long long存。

        数据水。。。否则高精。。。

    AC Code:

     1 // state expression:
     2 // dp[i][j] = max num
     3 // i: last '*' is in front of ith bit
     4 // j: used j '*'
     5 //
     6 // find the answer:
     7 // max dp[i][t] * cal_sec(i,len-1)
     8 //
     9 // transferring:
    10 // dp[i][j] = max dp[k][j-1] * cal_sec(k,i-1)
    11 //
    12 // boundary:
    13 // if input == 0: return 0
    14 // else dp[0] = 1, others = -1
    15 #include <iostream>
    16 #include <stdio.h>
    17 #include <string.h>
    18 #define MAX_N 45
    19 #define MAX_K 35
    20 
    21 using namespace std;
    22 
    23 int n,t;
    24 long long ans;
    25 long long dp[MAX_N][MAX_K];
    26 long long sec[MAX_N][MAX_N];
    27 string s;
    28 
    29 void read()
    30 {
    31     cin>>n>>t>>s;
    32 }
    33 
    34 long long cal_sec(int x,int y)
    35 {
    36     if(sec[x][y]!=-1) return sec[x][y];
    37     long long res=0;
    38     for(int i=x;i<=y;i++)
    39     {
    40         res=res*10+s[i]-'0';
    41     }
    42     return sec[x][y]=res;
    43 }
    44 
    45 void solve()
    46 {
    47     memset(sec,-1,sizeof(sec));
    48     memset(dp,-1,sizeof(dp));
    49     dp[0][0]=1;
    50     for(int i=1;i<n;i++)
    51     {
    52         for(int j=1;j<=t && j<=i;j++)
    53         {
    54             for(int k=0;k<i;k++)
    55             {
    56                 if(dp[k][j-1]!=-1)
    57                 {
    58                     dp[i][j]=max(dp[i][j],dp[k][j-1]*cal_sec(k,i-1));
    59                 }
    60             }
    61         }
    62     }
    63     ans=0;
    64     for(int i=0;i<n;i++)
    65     {
    66         if(dp[i][t]!=-1) ans=max(ans,dp[i][t]*cal_sec(i,n-1));
    67     }
    68 }
    69 
    70 void print()
    71 {
    72     cout<<ans<<endl;
    73 }
    74 
    75 int main()
    76 {
    77     read();
    78     solve();
    79     print();
    80 }
  • 相关阅读:
    iOS截取长图,自定义截取size
    工作
    UITableView适配iOS11
    利用脚本实现build号自动加一
    iOS原生与JS互调
    CSS高级技巧
    伪元素选择器
    CSS设置过渡
    CSS文本属性 二
    css设置圆角矩形
  • 原文地址:https://www.cnblogs.com/Leohh/p/7461324.html
Copyright © 2020-2023  润新知