P1018 乘积最大

题意:给出n位数,以及一个k,让我们将这n位数分成k+1位

  要求这k+1位相乘乘积最大;

思路:这是一道dp+高精度的题;

  1.我们首先来看看dp部分 dp【i】【j】表示将前i位分为j部分的最大值;

  于是遍历的时候,我们就

          k从小到打遍历

            i从小到大遍历

              分割位置从小到大遍历  (注:分割块数不能大于该范围的位数)

  2.高精度

    这道题涉及的是高精度乘法

    我们在dp【】【】上再加一维,来表示这个数

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<string>
 6 using namespace std;
 7 int dp[200][100][2000]={0},a[200][200][100]={0},n,k;
 8 int js(int x,int y,int z);
 9 int main(){
10     //输入并处理数据
11     //a[i][j]表示a的从i到j的数的大小
12     //a[1][n]存储完整的数
13     cin>>n>>k;
14     char tin;
15     a[1][n][0]=n;
16     //高精度保存
17     //所有数字位数保存在第[0]位
18     for(int i=1;i<=n;i++){
19         cin>>tin;
20         a[1][n][n-i+1]=tin-'0';
21     }
22     //预处理
23     for(int i=1;i<=n;i++){
24         for(int j=i;j<=n;j++){
25             a[i][j][0]=j-i+1;
26             for(int q=1;q<=a[i][j][0];q++){
27                 a[i][j][q]=a[1][n][q+i-1];
28             }
29         }
30     }
31     //计算
32     for(int i=1;i<=n;i++){
33         /*
34             用dp[i][j]保存将前i个数分成j段所能得到的最大值
35         */
36         for(int j=1;j<=i&&j<=k+1;j++){
37             /*
38                 计算dp[i][j]的最大值
39                 将前i个数字与分为最右边一段与左边最大值的乘积
40                 因为dp[i][j]的最大值为数字i-k段的值与dp[k][j-1]的值相乘的最大值
41                 k表示数字段的第一位
42                 dp[1][1]的
43             */
44             if(j==1){//只分成一段时,值为该段的数字
45                 dp[i][j][0]=i;
46                 for(int z=1;z<=i;z++){
47                     dp[i][j][z]=a[1][i][z];
48                 }
49             }
50             /*
51                 在前i个数中寻找一个分割点
52                 从该点分割得到的数最大
53                 该点前所留的数应比j(分成的段数)大
54             */
55             for(int z=i;z>=j-1;z--){//遍历z,找到最优的z
56                 js(i,j,z);
57             }
58         }
59     }
60     for(int i=dp[n][k+1][0];i>=1;i--){
61         cout<<dp[n][k+1][i];
62     }
63 }
64 int js(int x,int y,int z){
65     //计算乘积,保存在tsz内
66     /*
67         给定分割点z
68         前x个数,分成y段
69     */
70     int tsz[200]={0};
71     //高精度乘法
72     for(int i=1;i<=a[z][x][0];i++){//数字a的控制位
73         for(int j=1;j<=dp[z-1][y-1][0];j++){//最大值dp的控制位
74             tsz[i+j-1]+=a[z][x][i]*dp[z-1][y-1][j];
75         }
76     }
77     //计算进位与数字长度
78     //所有数字长度保存在数组[0]位
79     for(int i=1;i<=100;i++){
80         if(tsz[i])tsz[0]=i;
81         tsz[i+1]+=tsz[i]/10;
82         tsz[i]%=10;
83     }
84     //比较乘积与原数字的大小,与dp[x][y]比较
85     if(tsz[0]<dp[x][y][0]){
86         return 0;
87     }
88     for(int i=tsz[0];i>=0;i--){
89         if(i==0)return 2;//相同
90         if(tsz[i]>dp[x][y][i])break;
91         if(tsz[i]<dp[x][y][i])return 1;
92     }
93     //如果是更优解,保存该解
94     for(int i=tsz[0];i>=0;i--){
95         dp[x][y][i]=tsz[i];
96     }
97     return -1;
98 }

 

posted @ 2020-03-18 13:10  古比  阅读(153)  评论(0编辑  收藏  举报