RQNOJ 311 [NOIP2000]乘積最大:劃分型dp

Leohh發表於2017-09-01

題目連結: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 }

 

相關文章