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 }