题目描述
今年是国际数学联盟确定的“2000――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312, 当N=3,K=1时会有以下两种分法:
1) 3*12=36
2) 31*2=62
这时,符合题目要求的结果是:31*2=62
现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
输入输出格式
输入格式:
程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。
输出格式:
结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。
输入输出样例
输入样例#1:
4 2 1231
输出样例#1:
62
突然发现博客没DP题啊,然后就现水了一道占个位置。
一道经典的DP。首先,我们确定当前状态dp[i][j]表示 放的乘号个数为i、放到了第j个数字。
然后考虑转移方程。首先我们可以这样想,一个长度为j的序列当没有加入一个乘号时向其中加
入一个乘号是可以用O(N) 时间枚举最优解的(只用枚举乘号位置)。那么我们是不是可以考虑
用这种方法对于每一组K相同的状态,枚举出长度为j(j -> 1~N)的每一种最优解呢?因为我每一
次枚举K时对于前面的dp[K-1]的一组状态已经保证为最优解了。于是我们就有了状态转移方程:
dp[j][i]=max{dp[k][i-1]*num[k+1][j]};(1<=i<=K ;1<=j<=N;1<=k<=j)
其中num[a][b]表示从下标a到b的数字组成的数的大小(对于1231 num[2][4]=231) 时间复杂度O(N^2*m) 另外,一看到这道题本来应该是用高精度的,结果不知道为什么数据太水,Long Long就水过了。 对于恶心的long long 的读入,屈服于iostream黑恶势力……
#include<iostream> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int maxn=40; ll num[maxn][maxn]={ }; ll dp[maxn][20]={ }; int n,m; char s[50]; void init(int n){ memset(num,0,sizeof(num)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) num[i][i]=1LL*(s[i-1]-'0'); for(int i=1;i<=n-1;i++){ for(int j=i+1;j<=n;j++){ ll id=1LL*(s[j-1]-'0'); num[i][j]=num[i][j-1]*10+id; } } } int main(){ cin>>n>>m; cin>>s; init(n); for(int i=1;i<=n;i++) dp[i][0]=num[1][i]; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++) for(int k=1;k<=j;k++) if(dp[k][i-1]*num[k+1][j]>dp[j][i]) dp[j][i]=dp[k][i-1]*num[k+1][j]; } cout<<dp[n][m]; return 0; }
----------+--------+------18/3/27------+--------+--------
洛谷数据加强了QAQ……这里挂一个大整形高精度:
#include<cstring> #include<algorithm> using namespace std; namespace BIGINT { #define LL long long struct INT1024 { int len; int s[1030]; INT1024() {clean();} void clean() {memset(s, 0, sizeof(s)), len = 0;} void operator = (int x) { for(; x; x /= 10) s[len++] = x % 10; } void print() { for(int i = len - 1; i >= 0; --i) printf("%d", s[i]); putchar('\n'); } }; INT1024 c; INT1024 operator + (INT1024 a, INT1024 b) { int len = max(a.len, b.len); c.clean(); c.len=len; for(int i = 0;i < len; ++i) c.s[i] = a.s[i] + b.s[i]; for(int i = 0;i < len; ++i) c.s[i + 1] += c.s[i] / 10, c.s[i] %= 10; if(c.s[len]) ++c.len; return c; } INT1024 operator - (INT1024 a, INT1024 b) { c.clean(); for(int i = 0; i < a.len; ++i) { c.s[i] += a.s[i] - b.s[i]; if(c.s[i] < 0) c.s[i] += 10, --a.s[i + 1]; } int len = a.len - 1; for(; !c.s[len]; --len); c.len = len + 1; return c; } INT1024 operator * (INT1024 a, INT1024 b) { int len = a.len + b.len - 1; c.clean(); c.len = len; for(int i = 0;i < a.len; ++i) for(int j = 0; j < b.len; ++j) c.s[i + j] += a.s[i] * b.s[j]; for(int i = 0;i < len; ++i) c.s[i + 1] += c.s[i] / 10, c.s[i] %= 10; if(c.s[len]) ++c.len; return c; } }
没有帐号? 立即注册