整数划分(四)
-
描述
-
暑假来了,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
-
-
思路:
-
先求前一个乘号时,2位数的积、3位数的积....
-
再求二个乘号时,2位数的积、3位数的积....
-
-
其中最优解的结构特征:
-
dp[j][i]=MAX(dp[j][i],dp[k][i-1]*num[k+1][j]);
dp[k][i-1] 乘号前的数字
num[k+1][j] 乘号后的数字
-
AC代码:
-
#include<cstdio> #include<cstdlib> #include<cstring> #include <iostream> using namespace std; long long t,dp[25][25]; long long num[25][25]; char str[25]; long long MAX(long long a,long long b) { return a>b?a:b; } int main() { int i,j,k,m; scanf("%lld",&t); while(t--) { scanf("%s%d",str,&m); int l=strlen(str);m--; memset(dp,0,sizeof(dp)); memset(num,0,sizeof(num)); for(i=0;i<l;++i) { num[i][i]=str[i]-'0'; for(j=i+1;j<l;++j) { num[i][j]=num[i][j-1]*10+str[j]-'0'; } } for(i=0;i<l;++i){ for(j=0;j<l;++j) cout<<num[i][j]<<'\t'; cout<<endl; } for(i=0;i<l;++i) { dp[i][0]=num[0][i]; } for(i=1;i<=m;++i) //乘号位数 { for(j=i;j<l;++j) // 控制前j位数参与运算 { for(k=0;k<j;++k) //控制乘号位置 { dp[j][i]=MAX(dp[j][i],dp[k][i-1]*num[k+1][j]); } } } for(i=0;i<l;++i){ for(j=0;j<l;++j) cout<<dp[i][j]<<'\t'; cout<<endl; } printf("%lld\n",dp[l-1][m]); } return 0; }
样例输入 -
53241
-
-
得到NUM数组为:
-
-
-
DP数组为:
-
-
-
-
其中列数代表乘号数量,如第0列代表不加乘号,其中最后结果的最大值为53241(原数)
-
第1列代表加入一个乘号,其中第n行为前n位数参与运算,如第2行,有5和3参与运算加入一个乘号为15;
-
第3行,有5,3,2参与运算加入一个乘号的最大结果160。
-
-
题目中说:n<10ˇ19
-
但long long类型的最大数据为:9223372036854775807 存在越界风险啊...但OJ并没有报错....应该是测试数据不完善吧...
-
-
附加各种数据取值范围:
-
unsigned int 0~4294967295
int 2147483648~2147483647
unsigned long 0~4294967295
long 2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:1844674407370955161__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
- 第一行是一个整数T,表示有T组测试数据